diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/soc/qcom/smem.c | 47 |
1 files changed, 30 insertions, 17 deletions
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 817e2dfae12d..e20657dba6ce 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -314,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; @@ -330,7 +331,7 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem, 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", @@ -341,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 */ @@ -496,10 +503,11 @@ 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, *uncached_end, *cached_end; + 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; @@ -509,17 +517,18 @@ static void *qcom_smem_get_private(struct qcom_smem *smem, p_end = (void *)phdr + partition_size; e = phdr_to_first_private_entry(phdr); - uncached_end = phdr_to_last_private_entry(phdr); - cached_end = phdr_to_first_cached_entry(phdr); + end = phdr_to_last_private_entry(phdr); - if (WARN_ON(!IN_PARTITION_RANGE(uncached_end, 0, phdr, uncached_end) - || (void *)cached_end > p_end)) + if (WARN_ON((void *)end > p_end)) return ERR_PTR(-EINVAL); - - while ((e < uncached_end) && ((e + 1) < uncached_end)) { - if (e->canary != SMEM_PRIVATE_CANARY) - goto invalid_canary; + 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", + phdr->host0, phdr->host1); + return ERR_PTR(-EINVAL); + } if (le16_to_cpu(e->item) == item) { e_size = le32_to_cpu(e->size); @@ -530,10 +539,10 @@ static void *qcom_smem_get_private(struct qcom_smem *smem, else return ERR_PTR(-EINVAL); - item_ptr = entry_to_item(e); + item_ptr = entry_to_item(e); - if (WARN_ON(!IN_PARTITION_RANGE(item_ptr, entry_size, e, - uncached_end))) + if (WARN_ON(!IN_PARTITION_RANGE(item_ptr, entry_size, + e, end))) return ERR_PTR(-EINVAL); if (size != NULL) @@ -542,7 +551,11 @@ static void *qcom_smem_get_private(struct qcom_smem *smem, 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); |