virtcca inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I9Q85J
--------------------------------
enhance security for Confidential cVM tsi:
Signed-off-by: Shengjie Li lishengjie12@huawei.com --- arch/arm64/include/asm/cvm_smc.h | 22 +++---- arch/arm64/include/uapi/asm/cvm_tsi.h | 11 ++-- arch/arm64/kernel/cvm_tsi.c | 89 ++++++++++++++------------- 3 files changed, 64 insertions(+), 58 deletions(-)
diff --git a/arch/arm64/include/asm/cvm_smc.h b/arch/arm64/include/asm/cvm_smc.h index c4d56333e3..91688bc169 100644 --- a/arch/arm64/include/asm/cvm_smc.h +++ b/arch/arm64/include/asm/cvm_smc.h @@ -124,30 +124,30 @@ static inline unsigned long tsi_measurement_read(struct cvm_measurement *cvm_mea return res.a0; }
-static inline unsigned long tsi_attestation_token_init(struct cvm_attestation_cmd *attest_cmd) +static inline unsigned long tsi_attestation_token_init(unsigned char *challenge) { struct arm_smccc_res res; - unsigned char *challenge; + unsigned char *buf;
- challenge = kmalloc(CHALLENGE_SIZE, GFP_KERNEL); - if (!challenge) + buf = kmalloc(CHALLENGE_SIZE, GFP_KERNEL); + if (!buf) return -ENOMEM; - memcpy(challenge, attest_cmd->challenge, CHALLENGE_SIZE); + memcpy(buf, challenge, CHALLENGE_SIZE);
- arm_smccc_1_1_smc(SMC_TSI_ATTESTATION_TOKEN_INIT, virt_to_phys(challenge), &res); - kfree(challenge); + arm_smccc_1_1_smc(SMC_TSI_ATTESTATION_TOKEN_INIT, virt_to_phys(buf), &res); + kfree(buf);
return res.a0; }
-static inline unsigned long tsi_attestation_token_continue(struct cvm_attestation_cmd *attest_cmd) +static inline unsigned long tsi_attestation_token_continue(struct cvm_token_granule *token_granule) { struct arm_smccc_res res;
- arm_smccc_1_1_smc(SMC_TSI_ATTESTATION_TOKEN_CONTINUE, virt_to_phys(attest_cmd->granule_ipa), - attest_cmd->offset, attest_cmd->size, &res); + arm_smccc_1_1_smc(SMC_TSI_ATTESTATION_TOKEN_CONTINUE, virt_to_phys(token_granule->ipa), + token_granule->offset, token_granule->size, &res);
- attest_cmd->num_wr_bytes = res.a1; + token_granule->num_wr_bytes = res.a1;
return res.a0; } diff --git a/arch/arm64/include/uapi/asm/cvm_tsi.h b/arch/arm64/include/uapi/asm/cvm_tsi.h index 43e17a0da0..1ed4386db2 100644 --- a/arch/arm64/include/uapi/asm/cvm_tsi.h +++ b/arch/arm64/include/uapi/asm/cvm_tsi.h @@ -55,10 +55,13 @@ struct cvm_measurement_extend {
struct cvm_attestation_cmd { unsigned char challenge[CHALLENGE_SIZE]; /* input: challenge value */ - unsigned long token_size; /* return: challenge value */ - void *granule_head; - void *granule_ipa; /* IPA of the Granule to which the token will be written */ - unsigned long granule_count; + unsigned long token_size; /* return: token size */ +}; + +struct cvm_token_granule { + void *head; + void *ipa; /* IPA of the Granule to which the token will be written */ + unsigned long count; unsigned long offset; /* Offset within Granule to start of buffer in bytes */ unsigned long size; /* Size of buffer in bytes */ unsigned long num_wr_bytes; /* Number of bytes written to buffer */ diff --git a/arch/arm64/kernel/cvm_tsi.c b/arch/arm64/kernel/cvm_tsi.c index b48e5b17f4..252fe5352a 100644 --- a/arch/arm64/kernel/cvm_tsi.c +++ b/arch/arm64/kernel/cvm_tsi.c @@ -4,6 +4,7 @@ #include <linux/slab.h> #include <linux/miscdevice.h> #include <linux/preempt.h> +#include <asm/cvm_guest.h> #include <asm/cvm_smc.h> #include <asm/cvm_tsi.h>
@@ -16,20 +17,19 @@ struct attestation_token {
static struct attestation_token token;
+static DEFINE_SPINLOCK(lock); + static long tmm_tsi_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -static int tmm_tsi_release(struct inode *inode, struct file *file); static ssize_t tmm_token_read(struct file *file, char __user *user_buffer, size_t size, loff_t *offset);
static int tmm_get_tsi_version(struct cvm_tsi_version __user *arg); -static int tmm_get_attestation_token(struct cvm_attestation_cmd __user *arg, - struct attestation_token *attest_token); +static int tmm_get_attestation_token(struct cvm_attestation_cmd __user *arg); static int tmm_get_device_cert(struct cca_device_cert __user *arg);
static const struct file_operations tmm_tsi_fops = { .owner = THIS_MODULE, .read = tmm_token_read, - .release = tmm_tsi_release, .unlocked_ioctl = tmm_tsi_ioctl };
@@ -44,6 +44,9 @@ static int __init tmm_tsi_init(void) unsigned long ver; int ret;
+ if (!is_cvm_world()) + return -EIO; + ver = tsi_get_version(); if (ver == SMCCC_RET_NOT_SUPPORTED) { pr_err("tmm_tsi: SMC return not supported!\n"); @@ -56,6 +59,11 @@ static int __init tmm_tsi_init(void) return ret; }
+ /* Allocate a large memory */ + token.buf = kmalloc(GRANULE_SIZE * MAX_TOKEN_GRANULE_PAGE, GFP_KERNEL); + if (!token.buf) + return -ENOMEM; + pr_warn("tmm_tsi: module loaded (version %lu.%lu).\n", TSI_ABI_VERSION_GET_MAJOR(ver), TSI_ABI_VERSION_GET_MINOR(ver)); @@ -65,8 +73,10 @@ static int __init tmm_tsi_init(void)
static void __exit tmm_tsi_exit(void) { - if (token.buf != NULL) + if (token.buf != NULL) { + memset(token.buf, 0, GRANULE_SIZE * MAX_TOKEN_GRANULE_PAGE); kfree(token.buf); + } misc_deregister(&ioctl_dev); pr_warn("tmm_tsi: module unloaded.\n"); } @@ -80,7 +90,7 @@ static long tmm_tsi_ioctl(struct file *file, unsigned int cmd, unsigned long arg ret = tmm_get_tsi_version((struct cvm_tsi_version *)arg); break; case TMM_GET_ATTESTATION_TOKEN: - ret = tmm_get_attestation_token((struct cvm_attestation_cmd *)arg, &token); + ret = tmm_get_attestation_token((struct cvm_attestation_cmd *)arg); break; case TMM_GET_DEVICE_CERT: ret = tmm_get_device_cert((struct cca_device_cert *)arg); @@ -99,28 +109,25 @@ static ssize_t tmm_token_read(struct file *file, char __user *user_buffer, int ret; int to_copy;
- if (*offset >= token.size) + spin_lock(&lock); + if (*offset >= token.size) { + spin_unlock(&lock); return 0; + }
to_copy = min((int)size, (int)(token.size - *offset)); ret = copy_to_user(user_buffer, token.buf + *offset, to_copy); if (ret) { pr_err("tmm_tsi: copy token to user failed (%d)!\n", ret); + spin_unlock(&lock); return -1; }
*offset += to_copy; + spin_unlock(&lock); return to_copy; }
-static int tmm_tsi_release(struct inode *inode, struct file *file) -{ - if (token.buf != NULL) { - memset(token.buf, 0, GRANULE_SIZE * MAX_TOKEN_GRANULE_PAGE); - kfree(token.buf); - } - return 0; -}
static int tmm_get_tsi_version(struct cvm_tsi_version __user *arg) { @@ -141,65 +148,61 @@ static int tmm_get_tsi_version(struct cvm_tsi_version __user *arg) return 0; }
-static int tmm_get_attestation_token(struct cvm_attestation_cmd __user *arg, - struct attestation_token *attest_token) +static int tmm_get_attestation_token(struct cvm_attestation_cmd __user *arg) { unsigned long ret; - struct cvm_attestation_cmd cmd = {0}; + struct cvm_token_granule token_granule = {0}; + unsigned char challenge[CHALLENGE_SIZE];
- ret = copy_from_user(&(cmd.challenge), &(arg->challenge), sizeof(cmd.challenge)); + ret = copy_from_user(challenge, &(arg->challenge), CHALLENGE_SIZE); if (ret) { pr_err("tmm_tsi: copy data from user failed (%lu)!\n", ret); return -EFAULT; }
- /* Allocate a large memory */ - attest_token->buf = kmalloc(GRANULE_SIZE * MAX_TOKEN_GRANULE_PAGE, GFP_KERNEL); - if (!attest_token->buf) - return -ENOMEM; - cmd.granule_head = attest_token->buf; - cmd.granule_ipa = cmd.granule_head; + spin_lock(&lock); + token_granule.head = token.buf; + token_granule.ipa = token_granule.head;
- /* preempt_disable(); */ - - ret = tsi_attestation_token_init(&cmd); + ret = tsi_attestation_token_init(challenge); if (ret) { pr_err("tmm_tsi: tsi call tsi_attestation_token_init failed (%lu)!\n", ret); + spin_unlock(&lock); return -EIO; }
do { /* Retrieve one Granule of data per loop iteration */ - cmd.granule_ipa = cmd.granule_head + - (unsigned long)(cmd.granule_count * GRANULE_SIZE); - cmd.offset = 0; + token_granule.ipa = token_granule.head + + (unsigned long)(token_granule.count * GRANULE_SIZE); + token_granule.offset = 0;
do { /* Retrieve sub-Granule chunk of data per loop iteration */ - cmd.size = GRANULE_SIZE - cmd.offset; - ret = tsi_attestation_token_continue(&cmd); - cmd.offset += cmd.num_wr_bytes; - } while (ret == TSI_INCOMPLETE && cmd.offset < GRANULE_SIZE); + token_granule.size = GRANULE_SIZE - token_granule.offset; + ret = tsi_attestation_token_continue(&token_granule); + token_granule.offset += token_granule.num_wr_bytes; + } while (ret == TSI_INCOMPLETE && token_granule.offset < GRANULE_SIZE);
- cmd.granule_count += 1; - if (cmd.granule_count >= MAX_TOKEN_GRANULE_PAGE && ret == TSI_INCOMPLETE) { + token_granule.count += 1; + if (token_granule.count >= MAX_TOKEN_GRANULE_PAGE && ret == TSI_INCOMPLETE) { pr_err("tmm_tsi: macro MAX_TOKEN_GRANULE_PAGE (%d) is too small!\n", MAX_TOKEN_GRANULE_PAGE); + spin_unlock(&lock); return -ENOMEM; }
} while (ret == TSI_INCOMPLETE);
- /* preempt_enable(); */ - /* Send to user space the total size of the token */ - cmd.granule_count = cmd.granule_count - 1; - cmd.token_size = (unsigned long)(GRANULE_SIZE * cmd.granule_count) + cmd.offset; - attest_token->size = cmd.token_size; + token_granule.count = token_granule.count - 1; + token.size = (unsigned long)(GRANULE_SIZE * token_granule.count) + token_granule.offset;
- ret = copy_to_user(&(arg->token_size), &(cmd.token_size), sizeof(cmd.token_size)); + ret = copy_to_user(&(arg->token_size), &(token.size), sizeof(token.size)); if (ret) { pr_err("tmm_tsi: copy data to user failed (%lu)!\n", ret); + spin_unlock(&lock); return -EFAULT; } + spin_unlock(&lock);
return 0; }
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/8881 邮件列表地址:https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/7...
FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/8881 Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/7...