summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/soc/qcom/smem.c47
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);