diff options
author | Michael Bestas <mkbestas@lineageos.org> | 2024-04-21 01:43:48 +0300 |
---|---|---|
committer | Michael Bestas <mkbestas@lineageos.org> | 2024-04-21 01:43:48 +0300 |
commit | a590c593c64a2b6c882ade03ec01443d84ae0e4b (patch) | |
tree | 1b88c5f513adb80001781a8ae7dd51d41202e9fc /drivers/soc/qcom/smem.c | |
parent | b2c3134113250ea997e867384f95fb669f806e9c (diff) | |
parent | 4ce0e4a8d89f1df7a9fb1d7025543a743b244a23 (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
Diffstat (limited to 'drivers/soc/qcom/smem.c')
-rw-r--r-- | drivers/soc/qcom/smem.c | 60 |
1 files changed, 44 insertions, 16 deletions
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); |