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

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

Merge "qseecom: validate the inputs of __qseecom_send_modfd_resp"

parents eed72db0 cfa588d9
Loading
Loading
Loading
Loading
+56 −17
Original line number Diff line number Diff line
@@ -4152,41 +4152,80 @@ static int qseecom_reentrancy_send_resp(struct qseecom_dev_handle *data)
	return 0;
}

static int __qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
				void __user *argp, bool is_64bit_addr)
static int __validate_send_modfd_resp_inputs(struct qseecom_dev_handle *data,
			struct qseecom_send_modfd_listener_resp *resp,
			struct qseecom_registered_listener_list *this_lstnr)
{
	struct qseecom_send_modfd_listener_resp resp;
	int i;
	struct qseecom_registered_listener_list *this_lstnr = NULL;

	if (copy_from_user(&resp, argp, sizeof(resp))) {
		pr_err("copy_from_user failed");
	if (!data || !resp || !this_lstnr) {
		pr_err("listener handle or resp msg is null\n");
		return -EINVAL;
	}
	this_lstnr = __qseecom_find_svc(data->listener.id);
	if (this_lstnr == NULL)

	if (resp->resp_buf_ptr == NULL) {
		pr_err("resp buffer is null\n");
		return -EINVAL;
	}
	/* validate resp buf length */
	if ((resp->resp_len == 0) ||
			(resp->resp_len > this_lstnr->sb_length)) {
		pr_err("resp buf length %d not valid\n", resp->resp_len);
		return -EINVAL;
	}

	if (resp.resp_buf_ptr == NULL) {
		pr_err("Invalid resp_buf_ptr\n");
	if ((uintptr_t)resp->resp_buf_ptr > (ULONG_MAX - resp->resp_len)) {
		pr_err("Integer overflow in resp_len & resp_buf\n");
		return -EINVAL;
	}
	if ((uintptr_t)this_lstnr->user_virt_sb_base >
					(ULONG_MAX - this_lstnr->sb_length)) {
		pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
		return -EINVAL;
	}
	/* validate resp buf */
	if (((uintptr_t)resp->resp_buf_ptr <
		(uintptr_t)this_lstnr->user_virt_sb_base) ||
		((uintptr_t)resp->resp_buf_ptr >=
		((uintptr_t)this_lstnr->user_virt_sb_base +
				this_lstnr->sb_length)) ||
		(((uintptr_t)resp->resp_buf_ptr + resp->resp_len) >
		((uintptr_t)this_lstnr->user_virt_sb_base +
						this_lstnr->sb_length))) {
		pr_err("resp buf is out of shared buffer region\n");
		return -EINVAL;
	}

	/* validate offsets */
	for (i = 0; i < MAX_ION_FD; i++) {
		if (resp.ifd_data[i].cmd_buf_offset >= resp.resp_len) {
		if (resp->ifd_data[i].cmd_buf_offset >= resp->resp_len) {
			pr_err("Invalid offset %d = 0x%x\n",
				i, resp.ifd_data[i].cmd_buf_offset);
				i, resp->ifd_data[i].cmd_buf_offset);
			return -EINVAL;
		}
	}

	if ((resp.resp_buf_ptr < this_lstnr->user_virt_sb_base) ||
		((uintptr_t)resp.resp_buf_ptr >=
		((uintptr_t)this_lstnr->user_virt_sb_base +
				this_lstnr->sb_length))) {
		pr_err("resp_buf_ptr address not within shared buffer\n");
	return 0;
}

static int __qseecom_send_modfd_resp(struct qseecom_dev_handle *data,
				void __user *argp, bool is_64bit_addr)
{
	struct qseecom_send_modfd_listener_resp resp;
	struct qseecom_registered_listener_list *this_lstnr = NULL;

	if (copy_from_user(&resp, argp, sizeof(resp))) {
		pr_err("copy_from_user failed");
		return -EINVAL;
	}

	this_lstnr = __qseecom_find_svc(data->listener.id);
	if (this_lstnr == NULL)
		return -EINVAL;

	if (__validate_send_modfd_resp_inputs(data, &resp, this_lstnr))
		return -EINVAL;

	resp.resp_buf_ptr = this_lstnr->sb_virt +
		(uintptr_t)(resp.resp_buf_ptr - this_lstnr->user_virt_sb_base);