Merge tag 'LA.UM.8.3.c25-09700-sdm845.0' of https://git.codelinaro.org/clo/la/kernel/msm-4.9 into android13-4.9-sdm845
"LA.UM.8.3.c25-09700-sdm845.0" * tag 'LA.UM.8.3.c25-09700-sdm845.0' of https://git.codelinaro.org/clo/la/kernel/msm-4.9: securemsm-kernel: Fixed multiple listener registration on same fd msm: kgsl: Fix error handling during drawctxt switch msm: kgsl: Update the protect register list msm: kgsl: Do not release dma and anon buffers if unmap fails soc: qcom: smem: Add boundary checks for partitions msm: kgsl: Do not free sharedmem if it cannot be unmapped Conflicts: drivers/gpu/msm/kgsl_mmu.c Change-Id: I62a1cc70492f769d35a9e91e140b1cb987269224
This commit is contained in:
commit
2cb72020b2
5 changed files with 82 additions and 22 deletions
|
|
@ -1,4 +1,5 @@
|
|||
/* Copyright (c) 2002,2007-2018,2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
|
@ -629,8 +630,6 @@ int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
|
|||
if (drawctxt != NULL && kgsl_context_detached(&drawctxt->base))
|
||||
return -ENOENT;
|
||||
|
||||
trace_adreno_drawctxt_switch(rb, drawctxt);
|
||||
|
||||
/* Get a refcount to the new instance */
|
||||
if (drawctxt) {
|
||||
if (!_kgsl_context_get(&drawctxt->base))
|
||||
|
|
@ -643,7 +642,7 @@ int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
|
|||
}
|
||||
ret = adreno_ringbuffer_set_pt_ctx(rb, new_pt, drawctxt, flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err;
|
||||
|
||||
if (rb->drawctxt_active) {
|
||||
/* Wait for the timestamp to expire */
|
||||
|
|
@ -654,6 +653,13 @@ int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
|
|||
}
|
||||
}
|
||||
|
||||
trace_adreno_drawctxt_switch(rb, drawctxt);
|
||||
|
||||
rb->drawctxt_active = drawctxt;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
if (drawctxt)
|
||||
kgsl_context_put(&drawctxt->base);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
|
@ -964,5 +964,17 @@ int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb,
|
|||
else
|
||||
result = _set_ctxt_gpu(rb, drawctxt);
|
||||
|
||||
/*
|
||||
* In case ctxt switch fails, revert the pagetable back to the
|
||||
* original. Not reverting the pagetable will lead to incorrect
|
||||
* hardware state in the ringbuffer.
|
||||
*/
|
||||
if (result && (new_pt != cur_pt)) {
|
||||
if (cpu_path)
|
||||
result = _set_pagetable_cpu(rb, cur_pt);
|
||||
else
|
||||
result = _set_pagetable_gpu(rb, cur_pt);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (c) 2002,2007-2017,2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
|
|
|||
|
|
@ -353,7 +353,7 @@ struct qseecom_client_handle {
|
|||
|
||||
struct qseecom_listener_handle {
|
||||
u32 id;
|
||||
bool unregister_pending;
|
||||
bool register_pending;
|
||||
bool release_called;
|
||||
};
|
||||
|
||||
|
|
@ -1233,6 +1233,11 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
|
|||
struct qseecom_registered_listener_list *new_entry;
|
||||
struct qseecom_registered_listener_list *ptr_svc;
|
||||
|
||||
if (data->listener.register_pending) {
|
||||
pr_err("Already a listner registration is in process on this FD\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
|
||||
if (ret) {
|
||||
pr_err("copy_from_user failed\n");
|
||||
|
|
@ -1242,6 +1247,13 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
|
|||
rcvd_lstnr.sb_size))
|
||||
return -EFAULT;
|
||||
|
||||
ptr_svc = __qseecom_find_svc(data->listener.id);
|
||||
if (ptr_svc) {
|
||||
pr_err("Already a listener registered on this data: lid=%d\n",
|
||||
data->listener.id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ptr_svc = __qseecom_find_svc(rcvd_lstnr.listener_id);
|
||||
if (ptr_svc) {
|
||||
if (ptr_svc->unregister_pending == false) {
|
||||
|
|
@ -1276,12 +1288,15 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
|
|||
new_entry->svc.listener_id = rcvd_lstnr.listener_id;
|
||||
new_entry->sb_length = rcvd_lstnr.sb_size;
|
||||
new_entry->user_virt_sb_base = rcvd_lstnr.virt_sb_base;
|
||||
data->listener.register_pending = true;
|
||||
if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
|
||||
pr_err("qseecom_set_sb_memory failed for listener %d, size %d\n",
|
||||
rcvd_lstnr.listener_id, rcvd_lstnr.sb_size);
|
||||
kzfree(new_entry);
|
||||
data->listener.register_pending = false;
|
||||
return -ENOMEM;
|
||||
}
|
||||
data->listener.register_pending = false;
|
||||
|
||||
init_waitqueue_head(&new_entry->rcv_req_wq);
|
||||
init_waitqueue_head(&new_entry->listener_block_app_wq);
|
||||
|
|
|
|||
|
|
@ -85,6 +85,17 @@
|
|||
/* Max number of processors/hosts in a system */
|
||||
#define SMEM_HOST_COUNT 9
|
||||
|
||||
/* Entry range check
|
||||
* ptr >= start : Checks if ptr is greater than the start of access region
|
||||
* ptr + size >= ptr: Check for integer overflow (On 32bit system where ptr
|
||||
* and size are 32bits, ptr + size can wrap around to be a small integer)
|
||||
* ptr + size <= end: Checks if ptr+size is less than the end of access region
|
||||
*/
|
||||
#define IN_PARTITION_RANGE(ptr, size, start, end) \
|
||||
(((void *)(ptr) >= (void *)(start)) && \
|
||||
(((void *)(ptr) + (size)) >= (void *)(ptr)) && \
|
||||
(((void *)(ptr) + (size)) <= (void *)(end)))
|
||||
|
||||
/**
|
||||
* struct smem_proc_comm - proc_comm communication struct (legacy)
|
||||
* @command: current command to be executed
|
||||
|
|
@ -301,6 +312,7 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
|
|||
size_t size)
|
||||
{
|
||||
struct smem_private_entry *hdr, *end;
|
||||
struct smem_private_entry *next_hdr;
|
||||
struct smem_partition_header *phdr;
|
||||
size_t alloc_size;
|
||||
void *cached;
|
||||
|
|
@ -313,10 +325,11 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
|
|||
end = phdr_to_last_private_entry(phdr);
|
||||
cached = phdr_to_first_cached_entry(phdr);
|
||||
|
||||
if (WARN_ON((void *)end > p_end || (void *)cached > p_end))
|
||||
if (WARN_ON(!IN_PARTITION_RANGE(end, 0, phdr, cached) ||
|
||||
cached > p_end))
|
||||
return -EINVAL;
|
||||
|
||||
while (hdr < end) {
|
||||
while ((hdr < end) && ((hdr + 1) < end)) {
|
||||
if (hdr->canary != SMEM_PRIVATE_CANARY) {
|
||||
dev_err(smem->dev,
|
||||
"Found invalid canary in host %d:%d partition\n",
|
||||
|
|
@ -327,9 +340,15 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
|
|||
if (le16_to_cpu(hdr->item) == item)
|
||||
return -EEXIST;
|
||||
|
||||
hdr = private_entry_next(hdr);
|
||||
next_hdr = private_entry_next(hdr);
|
||||
|
||||
if (WARN_ON(next_hdr <= hdr))
|
||||
return -EINVAL;
|
||||
|
||||
hdr = next_hdr;
|
||||
}
|
||||
if (WARN_ON((void *)hdr > p_end))
|
||||
|
||||
if (WARN_ON((void *)hdr > (void *)end))
|
||||
return -EINVAL;
|
||||
|
||||
/* Check that we don't grow into the cached region */
|
||||
|
|
@ -484,7 +503,9 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
|
|||
{
|
||||
struct smem_partition_header *phdr;
|
||||
struct smem_private_entry *e, *end;
|
||||
struct smem_private_entry *next_e;
|
||||
void *item_ptr, *p_end;
|
||||
size_t entry_size = 0;
|
||||
u32 partition_size;
|
||||
u32 padding_data;
|
||||
u32 e_size;
|
||||
|
|
@ -499,7 +520,7 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
|
|||
if (WARN_ON((void *)end > p_end))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
while (e < end) {
|
||||
while ((e < end) && ((e + 1) < end)) {
|
||||
if (e->canary != SMEM_PRIVATE_CANARY) {
|
||||
dev_err(smem->dev,
|
||||
"Found invalid canary in host %d:%d partition\n",
|
||||
|
|
@ -508,25 +529,31 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
|
|||
}
|
||||
|
||||
if (le16_to_cpu(e->item) == item) {
|
||||
if (size != NULL) {
|
||||
e_size = le32_to_cpu(e->size);
|
||||
padding_data = le16_to_cpu(e->padding_data);
|
||||
e_size = le32_to_cpu(e->size);
|
||||
padding_data = le16_to_cpu(e->padding_data);
|
||||
|
||||
if (e_size < partition_size
|
||||
&& padding_data < e_size)
|
||||
*size = e_size - padding_data;
|
||||
else
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
if (e_size < partition_size && padding_data < e_size)
|
||||
entry_size = e_size - padding_data;
|
||||
else
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
item_ptr = entry_to_item(e);
|
||||
if (WARN_ON(item_ptr > p_end))
|
||||
|
||||
if (WARN_ON(!IN_PARTITION_RANGE(item_ptr, entry_size,
|
||||
e, end)))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (size != NULL)
|
||||
*size = entry_size;
|
||||
|
||||
return item_ptr;
|
||||
}
|
||||
|
||||
e = private_entry_next(e);
|
||||
next_e = private_entry_next(e);
|
||||
if (WARN_ON(next_e <= e))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
e = next_e;
|
||||
}
|
||||
if (WARN_ON((void *)e > p_end))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
|
|
|||
Loading…
Reference in a new issue