diff options
author | Sarannya S <quic_sarannya@quicinc.com> | 2023-09-22 13:13:58 +0530 |
---|---|---|
committer | Sambandam Chitra <quic_schitra@quicinc.com> | 2024-02-27 08:06:33 -0800 |
commit | 71dc69707730a693c883a94f2d390299b49ea144 (patch) | |
tree | 688b2ffb647797d608d89ec3d73219231872eda1 | |
parent | 7ee39cfc667e77c4c1bd87e63ffdda68948faa33 (diff) |
soc: qcom: smem: Add boundary checks for partitions
Add condition check to make sure that the end address
of private entry does not go out of partition.
Change-Id: I88b3c69d86d90905b214c13a8c632b134b487a49
Signed-off-by: Sarannya S <quic_sarannya@quicinc.com>
Signed-off-by: Pranav Mahesh Phansalkar <quic_pphansal@quicinc.com>
(cherry picked from commit d3154be15b022817c95973d77d67411da3ea71ef)
-rw-r--r-- | drivers/soc/qcom/smem.c | 63 |
1 files changed, 39 insertions, 24 deletions
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 2c77f9051a26..817e2dfae12d 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 @@ -314,7 +326,8 @@ 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) { @@ -483,8 +496,9 @@ static void *qcom_smem_get_private(struct qcom_smem *smem, unsigned item, size_t *size) { + struct smem_partition_header *phdr; - struct smem_private_entry *e, *end; + struct smem_private_entry *e, *uncached_end, *cached_end; void *item_ptr, *p_end; u32 partition_size; u32 padding_data; @@ -495,35 +509,36 @@ static void *qcom_smem_get_private(struct qcom_smem *smem, p_end = (void *)phdr + partition_size; e = phdr_to_first_private_entry(phdr); - end = phdr_to_last_private_entry(phdr); + uncached_end = phdr_to_last_private_entry(phdr); + cached_end = phdr_to_first_cached_entry(phdr); - if (WARN_ON((void *)end > p_end)) + if (WARN_ON(!IN_PARTITION_RANGE(uncached_end, 0, phdr, uncached_end) + || (void *)cached_end > p_end)) return ERR_PTR(-EINVAL); - while (e < end) { - if (e->canary != SMEM_PRIVATE_CANARY) { - dev_err(smem->dev, - "Found invalid canary in host %d:%d partition\n", - phdr->host0, phdr->host1); - return ERR_PTR(-EINVAL); - } + + while ((e < uncached_end) && ((e + 1) < uncached_end)) { + if (e->canary != SMEM_PRIVATE_CANARY) + goto invalid_canary; 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); - - if (e_size < partition_size - && padding_data < e_size) - *size = e_size - padding_data; - else - return ERR_PTR(-EINVAL); - } - - item_ptr = entry_to_item(e); - if (WARN_ON(item_ptr > p_end)) + e_size = le32_to_cpu(e->size); + padding_data = le16_to_cpu(e->padding_data); + + 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(!IN_PARTITION_RANGE(item_ptr, entry_size, e, + uncached_end))) + return ERR_PTR(-EINVAL); + + if (size != NULL) + *size = entry_size; + return item_ptr; } |