Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 02f0c5a1 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "qseecom: improve input validatation for qseecom_send_service_cmd"

parents 959940e4 86da5232
Loading
Loading
Loading
Loading
+87 −63
Original line number Diff line number Diff line
@@ -2622,11 +2622,6 @@ int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
		return -EINVAL;
	}

	if ((!req_ptr->cmd_req_buf) || (!req_ptr->resp_buf)) {
		pr_err("Invalid req/resp buffer, exiting\n");
		return -EINVAL;
	}

	/* Clients need to ensure req_buf is at base offset of shared buffer */
	if ((uintptr_t)req_ptr->cmd_req_buf !=
			data_ptr->client.user_virt_sb_base) {
@@ -2634,15 +2629,11 @@ int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
		return -EINVAL;
	}

	if (((uintptr_t)req_ptr->resp_buf <
			data_ptr->client.user_virt_sb_base) ||
		((uintptr_t)req_ptr->resp_buf >=
			(data_ptr->client.user_virt_sb_base +
			data_ptr->client.sb_length))){
		pr_err("response buffer address not within shared bufffer\n");
	if (data_ptr->client.sb_length <
			sizeof(struct qseecom_rpmb_provision_key)) {
		pr_err("shared buffer is too small to hold key type\n");
		return -EINVAL;
	}

	req_buf = data_ptr->client.sb_virt;

	send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
@@ -2669,36 +2660,6 @@ int __qseecom_process_fsm_key_svc_cmd(struct qseecom_dev_handle *data_ptr,
		return -EINVAL;
	}

	if (((uintptr_t)req_ptr->cmd_req_buf <
			data_ptr->client.user_virt_sb_base) ||
		((uintptr_t)req_ptr->cmd_req_buf >=
			(data_ptr->client.user_virt_sb_base +
			data_ptr->client.sb_length))) {
		pr_err("cmd buffer address not within shared bufffer\n");
		return -EINVAL;
	}

	if (((uintptr_t)req_ptr->resp_buf <
			data_ptr->client.user_virt_sb_base) ||
		((uintptr_t)req_ptr->resp_buf >=
			(data_ptr->client.user_virt_sb_base +
			data_ptr->client.sb_length))){
		pr_err("response buffer address not within shared bufffer\n");
		return -EINVAL;
	}

	if ((req_ptr->cmd_req_len == 0) || (req_ptr->resp_len == 0) ||
		req_ptr->cmd_req_len > data_ptr->client.sb_length ||
		req_ptr->resp_len > data_ptr->client.sb_length) {
		pr_err("cmd buffer length or response buffer length not valid\n");
		return -EINVAL;
	}

	if (req_ptr->cmd_req_len > UINT_MAX - req_ptr->resp_len) {
		pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n");
		return -EINVAL;
	}

	reqd_len_sb_in = req_ptr->cmd_req_len + req_ptr->resp_len;
	if (reqd_len_sb_in > data_ptr->client.sb_length) {
		pr_err("Not enough memory to fit cmd_buf and resp_buf. ");
@@ -2720,28 +2681,11 @@ int __qseecom_process_fsm_key_svc_cmd(struct qseecom_dev_handle *data_ptr,
	return ret;
}

static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
				void __user *argp)
static int __validate_send_service_cmd_inputs(struct qseecom_dev_handle *data,
				struct qseecom_send_svc_cmd_req *req)
{
	int ret = 0;
	struct qseecom_client_send_service_ireq send_svc_ireq;
	struct qseecom_client_send_fsm_key_req send_fsm_key_svc_ireq;
	struct qseecom_command_scm_resp resp;
	struct qseecom_send_svc_cmd_req req;
	void   *send_req_ptr;
	size_t req_buf_size;

	/*struct qseecom_command_scm_resp resp;*/

	if (copy_from_user(&req,
				(void __user *)argp,
				sizeof(req))) {
		pr_err("copy_from_user failed\n");
		return -EFAULT;
	}

	if ((req.resp_buf == NULL) || (req.cmd_req_buf == NULL)) {
		pr_err("cmd buffer or response buffer is null\n");
	if (!req || !req->resp_buf || !req->cmd_req_buf) {
		pr_err("req or cmd buffer or response buffer is null\n");
		return -EINVAL;
	}

@@ -2765,6 +2709,86 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
		return -EINVAL;
	}

	if (((uintptr_t)req->cmd_req_buf <
				data->client.user_virt_sb_base) ||
		((uintptr_t)req->cmd_req_buf >=
		(data->client.user_virt_sb_base + data->client.sb_length))) {
		pr_err("cmd buffer address not within shared bufffer\n");
		return -EINVAL;
	}
	if (((uintptr_t)req->resp_buf <
				data->client.user_virt_sb_base)  ||
		((uintptr_t)req->resp_buf >=
		(data->client.user_virt_sb_base + data->client.sb_length))) {
		pr_err("response buffer address not within shared bufffer\n");
		return -EINVAL;
	}
	if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
		(req->cmd_req_len > data->client.sb_length) ||
		(req->resp_len > data->client.sb_length)) {
		pr_err("cmd buf length or response buf length not valid\n");
		return -EINVAL;
	}
	if (req->cmd_req_len > UINT_MAX - req->resp_len) {
		pr_err("Integer overflow detected in req_len & rsp_len\n");
		return -EINVAL;
	}

	if ((req->cmd_req_len + req->resp_len) > data->client.sb_length) {
		pr_debug("Not enough memory to fit cmd_buf.\n");
		pr_debug("resp_buf. Required: %u, Available: %zu\n",
				(req->cmd_req_len + req->resp_len),
					data->client.sb_length);
		return -ENOMEM;
	}
	if ((uintptr_t)req->cmd_req_buf > (ULONG_MAX - req->cmd_req_len)) {
		pr_err("Integer overflow in req_len & cmd_req_buf\n");
		return -EINVAL;
	}
	if ((uintptr_t)req->resp_buf > (ULONG_MAX - req->resp_len)) {
		pr_err("Integer overflow in resp_len & resp_buf\n");
		return -EINVAL;
	}
	if (data->client.user_virt_sb_base >
					(ULONG_MAX - data->client.sb_length)) {
		pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
		return -EINVAL;
	}
	if ((((uintptr_t)req->cmd_req_buf + req->cmd_req_len) >
		((uintptr_t)data->client.user_virt_sb_base +
					data->client.sb_length)) ||
		(((uintptr_t)req->resp_buf + req->resp_len) >
		((uintptr_t)data->client.user_virt_sb_base +
					data->client.sb_length))) {
		pr_err("cmd buf or resp buf is out of shared buffer region\n");
		return -EINVAL;
	}
	return 0;
}

static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
				void __user *argp)
{
	int ret = 0;
	struct qseecom_client_send_service_ireq send_svc_ireq;
	struct qseecom_client_send_fsm_key_req send_fsm_key_svc_ireq;
	struct qseecom_command_scm_resp resp;
	struct qseecom_send_svc_cmd_req req;
	void   *send_req_ptr;
	size_t req_buf_size;

	/*struct qseecom_command_scm_resp resp;*/

	if (copy_from_user(&req,
				(void __user *)argp,
				sizeof(req))) {
		pr_err("copy_from_user failed\n");
		return -EFAULT;
	}

	if (__validate_send_service_cmd_inputs(data, &req))
		return -EINVAL;

	data->type = QSEECOM_SECURE_SERVICE;

	switch (req.cmd_id) {