Commit 2bd1be3f authored by hanliyang's avatar hanliyang
Browse files

virt/csv-guest: Provide interface for request of CSV3 attestation report

hygon inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IBGDHO


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: default avatarhanliyang <hanliyang@hygon.cn>
parent fee9c0d5
Loading
Loading
Loading
Loading
+122 −5
Original line number Diff line number Diff line
@@ -12,21 +12,28 @@
#include <linux/slab.h>
#include <linux/cc_platform.h>
#include <linux/cacheflush.h>
#include <linux/psp-hygon.h>

#include <uapi/linux/kvm_para.h>

#include <asm/csv.h>

#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 = {