summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Bestas <mkbestas@lineageos.org>2024-04-21 01:43:48 +0300
committerMichael Bestas <mkbestas@lineageos.org>2024-04-21 01:43:48 +0300
commita590c593c64a2b6c882ade03ec01443d84ae0e4b (patch)
tree1b88c5f513adb80001781a8ae7dd51d41202e9fc
parentb2c3134113250ea997e867384f95fb669f806e9c (diff)
parent4ce0e4a8d89f1df7a9fb1d7025543a743b244a23 (diff)
Merge tag 'LA.UM.8.4.c25-10700-8x98.0' of https://git.codelinaro.org/clo/la/kernel/msm-4.4 into android13-4.4-msm8998
"LA.UM.8.4.c25-10700-8x98.0" * tag 'LA.UM.8.4.c25-10700-8x98.0' of https://git.codelinaro.org/clo/la/kernel/msm-4.4: soc: qcom: smem: Add boundary checks for partitions Revert "soc: qcom: smem: Add boundary checks for partitions" msm: kgsl: Do not release dma and anon buffers if unmap fails msm: kgsl: Fix memory leak for anonymous buffers soc: qcom: smem: Add boundary checks for partitions msm: kgsl: Do not free sharedmem if it cannot be unmapped dsp: q6asm: Add check for ADSP payload size msm: kgsl: Prevent wrap around during user address mapping iommu: Fix missing return check of arm_lpae_init_pte q6asm: validate payload size before access dsp: afe: Add check for sidetone iir config copy size. q6core: Avoid OOB access in q6core q6voice: Add buf size check for cvs cal data. ASoC: msm-pcm-host-voice: Handle OOB access in hpcm_start. q6lsm: Address use after free for mmap handle. msm-pcm-host-voice: Check validity of session idx Asoc: check for invalid voice session id ASoC: msm-pcm-voip: Avoid integer underflow ASoC: msm-pcm-q6-v2: Add dsp buf check msm: kgsl: Make sure that pool pages don't have any extra references msm: kgsl: Use dma_buf_get() to get dma_buf structure Conflicts: drivers/gpu/msm/kgsl.c drivers/gpu/msm/kgsl_pool.c drivers/gpu/msm/kgsl_sharedmem.c sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c Change-Id: Ic2340d2ee0800279ae3ccbe1cb222c0ba2c2ae46
-rw-r--r--drivers/gpu/msm/kgsl.c103
-rw-r--r--drivers/gpu/msm/kgsl_mmu.c4
-rw-r--r--drivers/gpu/msm/kgsl_sharedmem.c8
-rw-r--r--drivers/soc/qcom/smem.c60
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c2
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c9
6 files changed, 117 insertions, 69 deletions
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 4b9f779e525e..c03345ec61f4 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2008-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 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
@@ -272,8 +272,15 @@ kgsl_mem_entry_create(void)
return entry;
}
#ifdef CONFIG_DMA_SHARED_BUFFER
-static void kgsl_destroy_ion(struct kgsl_dma_buf_meta *meta)
+static void kgsl_destroy_ion(struct kgsl_memdesc *memdesc)
{
+ struct kgsl_mem_entry *entry = container_of(memdesc,
+ struct kgsl_mem_entry, memdesc);
+ struct kgsl_dma_buf_meta *meta = entry->priv_data;
+
+ if (memdesc->priv & KGSL_MEMDESC_MAPPED)
+ return;
+
if (meta != NULL) {
dma_buf_unmap_attachment(meta->attach, meta->table,
DMA_FROM_DEVICE);
@@ -281,13 +288,47 @@ static void kgsl_destroy_ion(struct kgsl_dma_buf_meta *meta)
dma_buf_put(meta->dmabuf);
kfree(meta);
}
+
+ /*
+ * Ion takes care of freeing the sg_table for us so
+ * clear the sg table to ensure kgsl_sharedmem_free
+ * doesn't try to free it again
+ */
+ memdesc->sgt = NULL;
}
-#else
-static void kgsl_destroy_ion(struct kgsl_dma_buf_meta *meta)
+
+static struct kgsl_memdesc_ops kgsl_dmabuf_ops = {
+ .free = kgsl_destroy_ion,
+};
+#endif
+
+static void kgsl_destroy_anon(struct kgsl_memdesc *memdesc)
{
+ int i = 0, j;
+ struct scatterlist *sg;
+ struct page *page;
+ if (memdesc->priv & KGSL_MEMDESC_MAPPED)
+ return;
+
+ for_each_sg(memdesc->sgt->sgl, sg, memdesc->sgt->nents, i) {
+ page = sg_page(sg);
+ for (j = 0; j < (sg->length >> PAGE_SHIFT); j++) {
+ /*
+ * Mark the page in the scatterlist as dirty if they
+ * were writable by the GPU.
+ */
+ if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY))
+ set_page_dirty_lock(nth_page(page, j));
+
+ /*
+ * Put the page reference taken using get_user_pages
+ * during memdesc_sg_virt.
+ */
+ put_page(nth_page(page, j));
+ }
+ }
}
-#endif
void
kgsl_mem_entry_destroy(struct kref *kref)
@@ -310,41 +351,8 @@ kgsl_mem_entry_destroy(struct kref *kref)
atomic_long_sub(entry->memdesc.size,
&kgsl_driver.stats.mapped);
- /*
- * Ion takes care of freeing the sg_table for us so
- * clear the sg table before freeing the sharedmem
- * so kgsl_sharedmem_free doesn't try to free it again
- */
- if (memtype == KGSL_MEM_ENTRY_ION)
- entry->memdesc.sgt = NULL;
-
- if ((memtype == KGSL_MEM_ENTRY_USER)
- && !(entry->memdesc.flags & KGSL_MEMFLAGS_GPUREADONLY)) {
- int i = 0, j;
- struct scatterlist *sg;
- struct page *page;
- /*
- * Mark all of pages in the scatterlist as dirty since they
- * were writable by the GPU.
- */
- for_each_sg(entry->memdesc.sgt->sgl, sg,
- entry->memdesc.sgt->nents, i) {
- page = sg_page(sg);
- for (j = 0; j < (sg->length >> PAGE_SHIFT); j++)
- set_page_dirty_lock(nth_page(page, j));
- }
- }
-
kgsl_sharedmem_free(&entry->memdesc);
- switch (memtype) {
- case KGSL_MEM_ENTRY_ION:
- kgsl_destroy_ion(entry->priv_data);
- break;
- default:
- break;
- }
-
kfree(entry);
}
EXPORT_SYMBOL(kgsl_mem_entry_destroy);
@@ -2205,6 +2213,10 @@ out:
return ret;
}
+static struct kgsl_memdesc_ops kgsl_usermem_ops = {
+ .free = kgsl_destroy_anon,
+};
+
static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable,
struct kgsl_mem_entry *entry, unsigned long hostptr,
size_t offset, size_t size)
@@ -2220,6 +2232,7 @@ static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable,
entry->memdesc.pagetable = pagetable;
entry->memdesc.size = (uint64_t) size;
entry->memdesc.flags |= KGSL_MEMFLAGS_USERMEM_ADDR;
+ entry->memdesc.ops = &kgsl_usermem_ops;
if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
@@ -2530,11 +2543,6 @@ long kgsl_ioctl_gpuobj_import(struct kgsl_device_private *dev_priv,
return 0;
unmap:
- if (kgsl_memdesc_usermem_type(&entry->memdesc) == KGSL_MEM_ENTRY_ION) {
- kgsl_destroy_ion(entry->priv_data);
- entry->memdesc.sgt = NULL;
- }
-
kgsl_sharedmem_free(&entry->memdesc);
out:
@@ -2631,6 +2639,7 @@ static int kgsl_setup_dma_buf(struct kgsl_device *device,
entry->priv_data = meta;
entry->memdesc.pagetable = pagetable;
entry->memdesc.size = 0;
+ entry->memdesc.ops = &kgsl_dmabuf_ops;
/* USE_CPU_MAP is not impemented for ION. */
entry->memdesc.flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP);
entry->memdesc.flags |= KGSL_MEMFLAGS_USERMEM_ION;
@@ -2841,14 +2850,6 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
return result;
error_attach:
- switch (kgsl_memdesc_usermem_type(&entry->memdesc)) {
- case KGSL_MEM_ENTRY_ION:
- kgsl_destroy_ion(entry->priv_data);
- entry->memdesc.sgt = NULL;
- break;
- default:
- break;
- }
kgsl_sharedmem_free(&entry->memdesc);
error:
/* Clear gpuaddr here so userspace doesn't get any wrong ideas */
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 228f3396ae90..7aa68abbf91c 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2002,2007-2017,2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 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
@@ -498,6 +498,8 @@ kgsl_mmu_unmap(struct kgsl_pagetable *pagetable,
size = kgsl_memdesc_footprint(memdesc);
ret = pagetable->pt_ops->mmu_unmap(pagetable, memdesc);
+ if (ret)
+ return ret;
atomic_dec(&pagetable->stats.entries);
atomic_long_sub(size, &pagetable->stats.mapped);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index dfbea53c306b..39039b27d0e0 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -1,4 +1,5 @@
/* Copyright (c) 2002,2007-2017,2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023-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
@@ -407,6 +408,9 @@ done:
static void kgsl_page_alloc_free(struct kgsl_memdesc *memdesc)
{
+ if (memdesc->priv & KGSL_MEMDESC_MAPPED)
+ return;
+
kgsl_page_alloc_unmap_kernel(memdesc);
/* we certainly do not expect the hostptr to still be mapped */
BUG_ON(memdesc->hostptr);
@@ -510,6 +514,9 @@ static void kgsl_cma_coherent_free(struct kgsl_memdesc *memdesc)
{
struct dma_attrs *attrs = NULL;
+ if (memdesc->priv & KGSL_MEMDESC_MAPPED)
+ return;
+
if (memdesc->hostptr) {
if (memdesc->priv & KGSL_MEMDESC_SECURE) {
atomic_long_sub(memdesc->size,
@@ -874,6 +881,7 @@ void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc)
if (memdesc->sgt) {
sg_free_table(memdesc->sgt);
kfree(memdesc->sgt);
+ memdesc->sgt = NULL;
}
if (memdesc->pages)
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
index 6ab1d41b90ee..03e26c4417bf 100644
--- a/drivers/soc/qcom/smem.c
+++ b/drivers/soc/qcom/smem.c
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2015, Sony Mobile Communications AB.
* Copyright (c) 2012-2013, 2019 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
@@ -85,6 +86,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
@@ -302,6 +314,7 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
{
struct smem_partition_header *phdr;
struct smem_private_entry *hdr, *end;
+ struct smem_private_entry *next_hdr;
struct smem_partition_header *phdr;
size_t alloc_size;
void *cached;
@@ -314,10 +327,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",
@@ -328,9 +342,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 */
@@ -485,7 +505,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;
@@ -500,7 +522,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",
@@ -509,25 +531,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);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 00690c6817b9..bf2620c999b1 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 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
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 987c1cc099f8..91854735bb0f 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -12,6 +12,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/fs.h>
#include <linux/mutex.h>
@@ -2391,6 +2392,14 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
__func__, data->payload_size);
break;
case ASM_SESSION_CMDRSP_GET_MTMX_STRTR_PARAMS_V2:
+ payload_size = sizeof(struct asm_mtmx_strtr_get_params_cmdrsp);
+ if (data->payload_size < payload_size) {
+ pr_err("%s: insufficient payload size = %d\n",
+ __func__, data->payload_size);
+ spin_unlock_irqrestore(
+ &(session[session_id].session_lock), flags);
+ return -EINVAL;
+ }
q6asm_process_mtmx_get_param_rsp(ac, (void *) payload);
break;
case ASM_STREAM_PP_EVENT: