Loading drivers/misc/qseecom.c +56 −17 Original line number Diff line number Diff line Loading @@ -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); Loading Loading
drivers/misc/qseecom.c +56 −17 Original line number Diff line number Diff line Loading @@ -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); Loading