From 3b2f084372a77a5d1c339714a5ada1134084b207 Mon Sep 17 00:00:00 2001 From: hanliyang Date: Wed, 21 Aug 2024 11:40:14 +0800 Subject: [PATCH 1/3] x86/csv: Define ATTESTATION secure call command hygon inclusion category: feature CVE: NA --------------------------- Add definition of ATTESTATION secure call command and error codes of the secure call. Add struct csv_guest_user_data_attestation to support communicate between user-space and kernel-space. Add struct csv3_data_attestation_report to support communicate between X86 and PSP. Signed-off-by: hanliyang --- arch/x86/kernel/csv-shared.c | 23 ++++++++++++++++++++++- include/linux/psp-hygon.h | 22 ++++++++++++++++++++++ include/uapi/linux/psp-hygon.h | 13 +++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/csv-shared.c b/arch/x86/kernel/csv-shared.c index 0763195764daf..9383f5d0a4765 100644 --- a/arch/x86/kernel/csv-shared.c +++ b/arch/x86/kernel/csv-shared.c @@ -76,12 +76,33 @@ * CSV3_SECURE_CMD_UPDATE_SECURE_CALL_TABLE: * CSV3 guest wants to change the secure call pages. * The secure processor re-init the secure call context. + * + * CSV3_SECURE_CMD_REQ_REPORT: + * CSV3 guest wants to request attestation report. + * The secure processor will update the request message buffer and respond + * buffer to indicate the result of this request. */ enum csv3_secure_command_type { - CSV3_SECURE_CMD_ENC = 1, + /* The secure call request should below CSV3_SECURE_CMD_ACK */ + CSV3_SECURE_CMD_ENC = 0x1, CSV3_SECURE_CMD_DEC, CSV3_SECURE_CMD_RESET, CSV3_SECURE_CMD_UPDATE_SECURE_CALL_TABLE, + CSV3_SECURE_CMD_REQ_REPORT = 0x7, + + /* SECURE_CMD_ACK indicates secure call request can be handled */ + CSV3_SECURE_CMD_ACK = 0x6b, + + /* + * The following values are the error code of the secure call + * when firmware can't handling the specific secure call command + * as expected. + */ + CSV3_SECURE_CMD_ERROR_INTERNAL = 0x6c, + CSV3_SECURE_CMD_ERROR_INVALID_COMMAND = 0x6d, + CSV3_SECURE_CMD_ERROR_INVALID_PARAM = 0x6e, + CSV3_SECURE_CMD_ERROR_INVALID_ADDRESS = 0x6f, + CSV3_SECURE_CMD_ERROR_INVALID_LENGTH = 0x70, }; /* diff --git a/include/linux/psp-hygon.h b/include/linux/psp-hygon.h index 1888d9d725925..f1f7a23c606ea 100644 --- a/include/linux/psp-hygon.h +++ b/include/linux/psp-hygon.h @@ -306,6 +306,28 @@ struct csv3_data_dbg_read_mem { u32 size; /* In */ } __packed; +/** + * struct csv3_data_attestation_report - ATTESTATION secure call command parameters + * + * @handle: handle of the VM to process + * @resp_gpa: guest physical address to save the generated report + * @resp_length: length of the generated report + * @req_gpa: guest physical address of the input for the report + * @req_length: length of the input for the report + * @fw_error_code: firmware status code when generating the report + */ +struct csv3_data_attestation_report { + u32 handle; /* Out */ + u32 reserved1; + u64 resp_gpa; /* In */ + u8 reserved2[16]; + u32 resp_len; /* In/Out */ + u32 reserved3; + u64 req_gpa; /* In */ + u32 req_len; /* In,Out */ + u32 fw_error_code; /* Out */ +} __packed; + /** * struct csv3_data_send_encrypt_data - SEND_ENCRYPT_DATA command parameters * diff --git a/include/uapi/linux/psp-hygon.h b/include/uapi/linux/psp-hygon.h index 0e65afbeea3c2..7bb6a4f8b6e02 100644 --- a/include/uapi/linux/psp-hygon.h +++ b/include/uapi/linux/psp-hygon.h @@ -55,4 +55,17 @@ struct csv_user_data_download_firmware { __u32 length; /* In */ } __packed; +/** + * struct csv_guest_user_data_attestation - ATTESTATION command parameters + * + * @user_data: user specified data for the attestation report + * @mnonce: user's random nonce + * @hash: sm3 hash of the @user_data and @mnonce + */ +struct csv_guest_user_data_attestation { + __u8 user_data[64]; /* In */ + __u8 monce[16]; /* In */ + __u8 hash[32]; /* In */ +} __packed; + #endif /* __PSP_HYGON_USER_H__ */ From 09b8f520a099dea52711e5b2216d834d1b77d425 Mon Sep 17 00:00:00 2001 From: hanliyang Date: Wed, 21 Aug 2024 12:01:23 +0800 Subject: [PATCH 2/3] x86/csv: Add support for CSV3 ATTESTATION secure call hygon inclusion category: feature CVE: NA --------------------------- Expose the function to modules so that user can get attestation report of CSV3 guest through ioctl interface. It's suggested that the user make use of the ioctl interface of the module csv-guest. Signed-off-by: hanliyang --- arch/x86/include/asm/csv.h | 2 + arch/x86/kernel/csv.c | 73 +++++++++++++++++++++++++++++++++ arch/x86/mm/mem_encrypt_hygon.c | 1 + 3 files changed, 76 insertions(+) diff --git a/arch/x86/include/asm/csv.h b/arch/x86/include/asm/csv.h index e2fcaf4ded5f7..18ddf881a6fca 100644 --- a/arch/x86/include/asm/csv.h +++ b/arch/x86/include/asm/csv.h @@ -66,6 +66,7 @@ void __init csv_early_update_memory_dec(u64 vaddr, u64 pages); void __init csv_early_memory_enc_dec(u64 vaddr, u64 size, bool enc); void csv_memory_enc_dec(u64 vaddr, u64 pages, bool enc); +int csv3_issue_request_report(phys_addr_t paddr, size_t size); #else /* !CONFIG_HYGON_CSV */ @@ -79,6 +80,7 @@ static inline void __init csv_early_memory_enc_dec(u64 vaddr, u64 size, bool enc) { } static inline void csv_memory_enc_dec(u64 vaddr, u64 pages, bool enc) { } +static inline int csv3_issue_request_report(phys_addr_t paddr, size_t size) { return -EIO; } #endif /* CONFIG_HYGON_CSV */ diff --git a/arch/x86/kernel/csv.c b/arch/x86/kernel/csv.c index 4f80c97798deb..84a76ae3c0625 100644 --- a/arch/x86/kernel/csv.c +++ b/arch/x86/kernel/csv.c @@ -285,3 +285,76 @@ void csv_memory_enc_dec(u64 vaddr, u64 pages, bool enc) __csv3_memory_enc_dec(csv3_secure_call, vaddr & PAGE_MASK, pages, enc); } + +static void print_secure_call_error(enum csv3_secure_command_type code) +{ + switch (code) { + case CSV3_SECURE_CMD_ACK: + pr_debug("secure call: handled\n"); + break; + case CSV3_SECURE_CMD_ERROR_INTERNAL: + pr_err("secure call: internal error\n"); + break; + case CSV3_SECURE_CMD_ERROR_INVALID_COMMAND: + pr_err("secure call: unsupported cmd\n"); + break; + case CSV3_SECURE_CMD_ERROR_INVALID_PARAM: + pr_err("secure call: invalid param\n"); + break; + case CSV3_SECURE_CMD_ERROR_INVALID_ADDRESS: + pr_err("secure call: invalid address\n"); + break; + case CSV3_SECURE_CMD_ERROR_INVALID_LENGTH: + pr_err("secure call: invalid length\n"); + break; + default: + pr_err("secure call: shouldn't reach here\n"); + break; + } +} + +int csv3_issue_request_report(phys_addr_t paddr, size_t size) +{ + struct secure_call_pages *sc_page_info; + struct csv3_secure_call_cmd *sc_wr, *sc_rd; + unsigned long flags; + int sc_page_idx; + enum csv3_secure_command_type sc_return_code; + + /* + * secure call pages needs to access with IRQs disabled because it is + * using a per-CPU data. + */ + local_irq_save(flags); + + sc_page_info = this_cpu_read(secure_call_data); + sc_page_idx = this_cpu_read(secure_call_page_idx); + + sc_wr = sc_page_idx ? &sc_page_info->page_a : &sc_page_info->page_b; + sc_rd = sc_page_idx ? &sc_page_info->page_b : &sc_page_info->page_a; + + sc_wr->cmd_type = CSV3_SECURE_CMD_REQ_REPORT; + sc_wr->nums = 1; + sc_wr->unused = 0; + sc_wr->entry[0].base_address = (u64)paddr; + sc_wr->entry[0].size = size; + + /* + * Write command in sc_wr must be done before retrieve status code + * from sc_rd, and it's ensured by the smp_mb below. + */ + smp_mb(); + + sc_return_code = sc_rd->cmd_type; + + this_cpu_write(secure_call_page_idx, sc_page_idx ^ 1); + + /* Leave per-CPU data access */ + local_irq_restore(flags); + + /* Print return code of the secure call */ + print_secure_call_error(sc_return_code); + + return sc_return_code == CSV3_SECURE_CMD_ACK ? 0 : -EIO; +} +EXPORT_SYMBOL_GPL(csv3_issue_request_report); diff --git a/arch/x86/mm/mem_encrypt_hygon.c b/arch/x86/mm/mem_encrypt_hygon.c index 1871850cbb604..52ec3fa041feb 100644 --- a/arch/x86/mm/mem_encrypt_hygon.c +++ b/arch/x86/mm/mem_encrypt_hygon.c @@ -130,6 +130,7 @@ bool noinstr csv3_active(void) else return false; } +EXPORT_SYMBOL_GPL(csv3_active); /******************************************************************************/ /**************************** CSV3 CMA interfaces *****************************/ From 83b4ebd3f9cbd783a0eaafbf8e8ffb24d5cd4ad3 Mon Sep 17 00:00:00 2001 From: hanliyang Date: Wed, 21 Aug 2024 14:55:06 +0800 Subject: [PATCH 3/3] virt/csv-guest: Provide interface for request of CSV3 attestation report hygon inclusion category: feature CVE: NA --------------------------- This change allows user in the CSV3 guest to get attestation report. Currently, the input from user-space for CSV3 attestation report is same as that for CSV attestation report. Signed-off-by: hanliyang --- drivers/virt/coco/csv-guest/csv-guest.c | 127 +++++++++++++++++++++++- 1 file changed, 122 insertions(+), 5 deletions(-) diff --git a/drivers/virt/coco/csv-guest/csv-guest.c b/drivers/virt/coco/csv-guest/csv-guest.c index 7db8177637ce1..6a77c68b19b4a 100644 --- a/drivers/virt/coco/csv-guest/csv-guest.c +++ b/drivers/virt/coco/csv-guest/csv-guest.c @@ -12,21 +12,28 @@ #include #include #include +#include #include +#include + #include "csv-guest.h" -static long csv_get_report(void __user *argp) +/* Mutex to serialize the command handling. */ +static DEFINE_MUTEX(csv_cmd_mutex); + +static int csv_get_report(unsigned long arg) { u8 *csv_report; long ret; struct csv_report_req req; - if (copy_from_user(&req, argp, sizeof(struct csv_report_req))) + if (copy_from_user(&req, (void __user *)arg, + sizeof(struct csv_report_req))) return -EFAULT; - if (req.len < CSV_REPORT_INPUT_DATA_LEN) + if (req.len < CSV_REPORT_INPUT_DATA_LEN || !req.report_data) return -EINVAL; csv_report = kzalloc(req.len, GFP_KERNEL); @@ -54,14 +61,124 @@ static long csv_get_report(void __user *argp) return ret; } +static int csv3_get_report(unsigned long arg) +{ + struct csv_report_req input; + struct page *page = NULL; + struct csv3_data_attestation_report *cmd_buff = NULL; + void *req_buff = NULL; + void *resp_buff = NULL; + int ret; + + if (copy_from_user(&input, (void __user *)arg, sizeof(input))) + return -EFAULT; + + if (!input.len || !input.report_data) + return -EINVAL; + + /* Use alloc_page for alignment */ + page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); + if (!page) + return -ENOMEM; + cmd_buff = (struct csv3_data_attestation_report *)page_address(page); + + /* + * Query the firmware to get minimum length of request buffer and + * respond buffer. + */ + ret = csv3_issue_request_report(__pa(cmd_buff), sizeof(*cmd_buff)); + + /* + * The input.len must be the maxinum length of the req and resp buffer + * at least, otherwise return with error. + */ + if (input.len < max(cmd_buff->req_len, cmd_buff->resp_len)) { + ret = -EINVAL; + goto err; + } + + /* Use alloc_page for alignment */ + page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); + if (!page) { + ret = -ENOMEM; + goto err; + } + req_buff = page_address(page); + + /* Use alloc_page for alignment */ + page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); + if (!page) { + ret = -ENOMEM; + goto err; + } + resp_buff = page_address(page); + + /* Copy user's input data */ + if (copy_from_user(req_buff, input.report_data, cmd_buff->req_len)) { + ret = -EFAULT; + goto err; + } + + /* + * The req_len and resp_len fields has already been filled by firmware + * when we query the lengths from firmware. + */ + cmd_buff->req_gpa = __pa(req_buff); + cmd_buff->resp_gpa = __pa(resp_buff); + + ret = csv3_issue_request_report(__pa(cmd_buff), sizeof(*cmd_buff)); + if (ret || (!ret && cmd_buff->fw_error_code)) { + pr_err("%s: fail to generate report, fw_error:%#x ret:%d\n", + __func__, cmd_buff->fw_error_code, ret); + ret = -EIO; + goto err; + } + + /* Copy attestation report to user */ + if (copy_to_user(input.report_data, resp_buff, cmd_buff->resp_len)) + ret = -EFAULT; + +err: + if (resp_buff) + free_page((unsigned long)resp_buff); + if (req_buff) + free_page((unsigned long)req_buff); + if (cmd_buff) + free_page((unsigned long)cmd_buff); + + return ret; +} + +static int get_report(unsigned long arg) +{ + int ret = -ENOTTY; + + lockdep_assert_held(&csv_cmd_mutex); + + if (csv3_active()) + ret = csv3_get_report(arg); + else if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) + ret = csv_get_report(arg); + return ret; +} + static long csv_guest_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { + int ret = -ENOTTY; + + mutex_lock(&csv_cmd_mutex); + switch (cmd) { case CSV_CMD_GET_REPORT: - return csv_get_report((void __user *)arg); + ret = get_report(arg); + break; default: - return -ENOTTY; + break; } + + mutex_unlock(&csv_cmd_mutex); + + return ret; } static const struct file_operations csv_guest_fops = {