Skip to content

Commit

Permalink
soc: qcom: smem: Add boundary checks for partitions
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Pranav Mahesh Phansalkar <[email protected]>
(cherry picked from commit ec66552d05105ec9c2b9a094d9420a64520b7500)
  • Loading branch information
quic-pphansal authored and zeelog committed Oct 26, 2024
1 parent 4cd9867 commit 48e9bf8
Showing 1 changed file with 43 additions and 16 deletions.
59 changes: 43 additions & 16 deletions drivers/soc/qcom/smem.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,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
Expand Down Expand Up @@ -301,6 +312,7 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
size_t size)
{
struct smem_private_entry *hdr, *end;
struct smem_private_entry *next_hdr;
struct smem_partition_header *phdr;
size_t alloc_size;
void *cached;
Expand All @@ -313,10 +325,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",
Expand All @@ -327,9 +340,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 */
Expand Down Expand Up @@ -484,7 +503,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;
Expand All @@ -499,7 +520,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",
Expand All @@ -508,25 +529,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);
Expand Down

0 comments on commit 48e9bf8

Please sign in to comment.