* [PATCH 0/2] Add automotive SMEM hardening for Qualcomm platforms
@ 2026-08-20 11:34 Albert Esteve
2026-08-20 11:34 ` [PATCH 1/2] soc: qcom: smem: add boundary checks for partitions Albert Esteve
2026-08-20 11:34 ` [PATCH 2/2] soc: qcom: smem: ignore multi remote host partitions Albert Esteve
0 siblings, 2 replies; 5+ messages in thread
From: Albert Esteve @ 2026-08-20 11:34 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, linux-kernel, Albert Esteve, Sudeepgoud Patil,
Sarannya S, Pranav Mahesh Phansalkar, Tony Truong
The Qualcomm SMEM driver manages shared memory partitions used for
inter-processor communication on Qualcomm SoCs, including the
automotive SA8775P platform. Vendor trees carry additional validation
and partition-enumeration logic that is not yet present in master.
Patch 1 adds boundary checks when walking private SMEM partition
entries, ensuring traversal does not read past the end of a partition.
Patch 2 skips multi-remote-host partitions during enumeration. SMEM
now supports partitions involving more than one remote host, but the
driver does not implement that case yet.
Both patches are based on public vendor patches from Qualcomm [1][2].
Adapted for master. In particular:
- Dropped the xarray partition rework, which is already present in
master (79602b750b96c, "soc: qcom: smem: Switch partitions to
xarray")
Built on master (Linux 7.2.0-rc6+), and tested on Qualcomm SA8775P
Ride V3 board. SMEM platform device binds and initializes successfully.
[1] https://git.codelinaro.org/clo/la/kernel/qcom/-/commit/3e521f2641c8f01f00fd74a088206942ce23d6d4
[2] https://git.codelinaro.org/clo/la/kernel/qcom/-/commit/842dd28b0276b3824a607e067b3c20e266bcf230
Signed-off-by: Albert Esteve <aesteve@redhat.com>
---
Sudeepgoud Patil (1):
soc: qcom: smem: add boundary checks for partitions
Tony Truong (1):
soc: qcom: smem: ignore multi remote host partitions
drivers/soc/qcom/smem.c | 111 ++++++++++++++++++++++++++++++++++--------------
1 file changed, 78 insertions(+), 33 deletions(-)
---
base-commit: c21bb4193868a8de71fc4693fa741e195fdf5d86
change-id: 20260819-port-smem-7518c77c9415
Best regards,
--
Albert Esteve <aesteve@redhat.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] soc: qcom: smem: add boundary checks for partitions
2026-08-20 11:34 [PATCH 0/2] Add automotive SMEM hardening for Qualcomm platforms Albert Esteve
@ 2026-08-20 11:34 ` Albert Esteve
2026-08-31 22:54 ` Bjorn Andersson
2026-08-20 11:34 ` [PATCH 2/2] soc: qcom: smem: ignore multi remote host partitions Albert Esteve
1 sibling, 1 reply; 5+ messages in thread
From: Albert Esteve @ 2026-08-20 11:34 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, linux-kernel, Albert Esteve, Sudeepgoud Patil,
Sarannya S, Pranav Mahesh Phansalkar
From: Sudeepgoud Patil <quic_sudeepgo@quicinc.com>
Add condition check to make sure that the end address
of private entry does not go out of partition.
Signed-off-by: Sarannya S <quic_sarannya@quicinc.com>
Signed-off-by: Pranav Mahesh Phansalkar <quic_pphansal@quicinc.com>
Signed-off-by: Sudeepgoud Patil <quic_sudeepgo@quicinc.com>
Signed-off-by: Albert Esteve <aesteve@redhat.com>
---
drivers/soc/qcom/smem.c | 105 +++++++++++++++++++++++++++++++++---------------
1 file changed, 72 insertions(+), 33 deletions(-)
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
index afb21a778fe7b..194ffb2ac010f 100644
--- a/drivers/soc/qcom/smem.c
+++ b/drivers/soc/qcom/smem.c
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2015, Sony Mobile Communications AB.
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/hwspinlock.h>
@@ -85,6 +86,17 @@
/* Processor/host identifier for the global partition */
#define SMEM_GLOBAL_HOST 0xfffe
+/* 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
@@ -403,6 +415,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;
@@ -415,19 +428,25 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
end = phdr_to_last_uncached_entry(phdr);
cached = phdr_to_last_cached_entry(phdr);
- if (WARN_ON((void *)end > p_end || 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)
goto bad_canary;
if (le16_to_cpu(hdr->item) == item)
return -EEXIST;
- hdr = uncached_entry_next(hdr);
+ next_hdr = uncached_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 */
@@ -587,9 +606,11 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
unsigned item,
size_t *size)
{
- struct smem_private_entry *e, *end;
+ struct smem_private_entry *e, *uncached_end, *cached_end;
+ struct smem_private_entry *next_e;
struct smem_partition_header *phdr;
void *item_ptr, *p_end;
+ size_t entry_size = 0;
u32 padding_data;
u32 e_size;
@@ -597,67 +618,85 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
p_end = (void *)phdr + part->size;
e = phdr_to_first_uncached_entry(phdr);
- end = phdr_to_last_uncached_entry(phdr);
+ uncached_end = phdr_to_last_uncached_entry(phdr);
+ cached_end = phdr_to_last_cached_entry(phdr);
+
+ if (WARN_ON(!IN_PARTITION_RANGE(uncached_end, 0, phdr, cached_end)
+ || (void *)cached_end > p_end))
+ return ERR_PTR(-EINVAL);
- while (e < end) {
+ 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);
+ e_size = le32_to_cpu(e->size);
+ padding_data = le16_to_cpu(e->padding_data);
- if (WARN_ON(e_size > part->size || padding_data > e_size))
- return ERR_PTR(-EINVAL);
+ if (e_size < part->size && padding_data < e_size)
+ entry_size = e_size - padding_data;
+ else
+ return ERR_PTR(-EINVAL);
- *size = e_size - padding_data;
- }
+ item_ptr = uncached_entry_to_item(e);
- item_ptr = uncached_entry_to_item(e);
- if (WARN_ON(item_ptr > p_end))
+ 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;
}
- e = uncached_entry_next(e);
- }
+ next_e = uncached_entry_next(e);
+ if (WARN_ON(next_e <= e))
+ return ERR_PTR(-EINVAL);
- if (WARN_ON((void *)e > p_end))
+ e = next_e;
+ }
+ if (WARN_ON((void *)e > (void *)uncached_end))
return ERR_PTR(-EINVAL);
/* Item was not found in the uncached list, search the cached list */
+ if (cached_end == p_end)
+ return ERR_PTR(-ENOENT);
+
e = phdr_to_first_cached_entry(phdr, part->cacheline);
- end = phdr_to_last_cached_entry(phdr);
- if (WARN_ON((void *)e < (void *)phdr || (void *)end > p_end))
+ if (WARN_ON(!IN_PARTITION_RANGE(cached_end, 0, uncached_end, p_end) ||
+ !IN_PARTITION_RANGE(e, sizeof(*e), cached_end, p_end)))
return ERR_PTR(-EINVAL);
- while (e > end) {
+ while (e > cached_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);
+ e_size = le32_to_cpu(e->size);
+ padding_data = le16_to_cpu(e->padding_data);
- if (WARN_ON(e_size > part->size || padding_data > e_size))
- return ERR_PTR(-EINVAL);
-
- *size = e_size - padding_data;
- }
+ if (e_size < part->size && padding_data < e_size)
+ entry_size = e_size - padding_data;
+ else
+ return ERR_PTR(-EINVAL);
- item_ptr = cached_entry_to_item(e);
- if (WARN_ON(item_ptr < (void *)phdr))
+ item_ptr = cached_entry_to_item(e);
+ if (WARN_ON(!IN_PARTITION_RANGE(item_ptr, entry_size, cached_end, e)))
return ERR_PTR(-EINVAL);
+ if (size != NULL)
+ *size = entry_size;
+
return item_ptr;
}
- e = cached_entry_next(e, part->cacheline);
+ next_e = cached_entry_next(e, part->cacheline);
+ if (WARN_ON(next_e >= e))
+ return ERR_PTR(-EINVAL);
+
+ e = next_e;
}
if (WARN_ON((void *)e < (void *)phdr))
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/2] soc: qcom: smem: ignore multi remote host partitions
2026-08-20 11:34 [PATCH 0/2] Add automotive SMEM hardening for Qualcomm platforms Albert Esteve
2026-08-20 11:34 ` [PATCH 1/2] soc: qcom: smem: add boundary checks for partitions Albert Esteve
@ 2026-08-20 11:34 ` Albert Esteve
1 sibling, 0 replies; 5+ messages in thread
From: Albert Esteve @ 2026-08-20 11:34 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, linux-kernel, Albert Esteve, Tony Truong
From: Tony Truong <quic_truong@quicinc.com>
SMEM now supports more than just 1-to-1 partitions. It is possible for
a partition to have multiple remote host and the logic to handle that
does not exist. For now, skip all partitions which has multiple remote
hosts.
Signed-off-by: Tony Truong <quic_truong@quicinc.com>
Signed-off-by: Albert Esteve <aesteve@redhat.com>
---
drivers/soc/qcom/smem.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
index 194ffb2ac010f..8e079d2381535 100644
--- a/drivers/soc/qcom/smem.c
+++ b/drivers/soc/qcom/smem.c
@@ -86,6 +86,9 @@
/* Processor/host identifier for the global partition */
#define SMEM_GLOBAL_HOST 0xfffe
+/* Processor/host identifier for multi host partition */
+#define SMEM_MULTI_HOST 0xfffc
+
/* 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
@@ -1081,6 +1084,9 @@ qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
else
continue;
+ if (remote_host == SMEM_MULTI_HOST)
+ continue;
+
if (xa_load(&smem->partitions, remote_host)) {
dev_err(smem->dev, "duplicate host %u\n", remote_host);
return -EINVAL;
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] soc: qcom: smem: add boundary checks for partitions
2026-08-20 11:34 ` [PATCH 1/2] soc: qcom: smem: add boundary checks for partitions Albert Esteve
@ 2026-08-31 22:54 ` Bjorn Andersson
2026-09-01 7:04 ` Albert Esteve
0 siblings, 1 reply; 5+ messages in thread
From: Bjorn Andersson @ 2026-08-31 22:54 UTC (permalink / raw)
To: Albert Esteve
Cc: Konrad Dybcio, linux-arm-msm, linux-kernel, Sudeepgoud Patil,
Sarannya S, Pranav Mahesh Phansalkar
On Thu, Aug 20, 2026 at 01:34:18PM +0200, Albert Esteve wrote:
> From: Sudeepgoud Patil <quic_sudeepgo@quicinc.com>
>
> Add condition check to make sure that the end address
> of private entry does not go out of partition.
>
> Signed-off-by: Sarannya S <quic_sarannya@quicinc.com>
> Signed-off-by: Pranav Mahesh Phansalkar <quic_pphansal@quicinc.com>
> Signed-off-by: Sudeepgoud Patil <quic_sudeepgo@quicinc.com>
> Signed-off-by: Albert Esteve <aesteve@redhat.com>
I'm sorry, Albert. Sudeepgoud messed up the authorship vs signed-off-by
chain here. The author should be "Sarannya", as that's the first
signed-off-by.
PS. It would also be nice if this was submitted with updated email
addresses and copyright statement. But I'd not expect you to fix that.
Regards,
Bjorn
> ---
> drivers/soc/qcom/smem.c | 105 +++++++++++++++++++++++++++++++++---------------
> 1 file changed, 72 insertions(+), 33 deletions(-)
>
> diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
> index afb21a778fe7b..194ffb2ac010f 100644
> --- a/drivers/soc/qcom/smem.c
> +++ b/drivers/soc/qcom/smem.c
> @@ -2,6 +2,7 @@
> /*
> * Copyright (c) 2015, Sony Mobile Communications AB.
> * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
> */
>
> #include <linux/hwspinlock.h>
> @@ -85,6 +86,17 @@
> /* Processor/host identifier for the global partition */
> #define SMEM_GLOBAL_HOST 0xfffe
>
> +/* 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
> @@ -403,6 +415,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;
> @@ -415,19 +428,25 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
> end = phdr_to_last_uncached_entry(phdr);
> cached = phdr_to_last_cached_entry(phdr);
>
> - if (WARN_ON((void *)end > p_end || 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)
> goto bad_canary;
> if (le16_to_cpu(hdr->item) == item)
> return -EEXIST;
>
> - hdr = uncached_entry_next(hdr);
> + next_hdr = uncached_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 */
> @@ -587,9 +606,11 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
> unsigned item,
> size_t *size)
> {
> - struct smem_private_entry *e, *end;
> + struct smem_private_entry *e, *uncached_end, *cached_end;
> + struct smem_private_entry *next_e;
> struct smem_partition_header *phdr;
> void *item_ptr, *p_end;
> + size_t entry_size = 0;
> u32 padding_data;
> u32 e_size;
>
> @@ -597,67 +618,85 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
> p_end = (void *)phdr + part->size;
>
> e = phdr_to_first_uncached_entry(phdr);
> - end = phdr_to_last_uncached_entry(phdr);
> + uncached_end = phdr_to_last_uncached_entry(phdr);
> + cached_end = phdr_to_last_cached_entry(phdr);
> +
> + if (WARN_ON(!IN_PARTITION_RANGE(uncached_end, 0, phdr, cached_end)
> + || (void *)cached_end > p_end))
> + return ERR_PTR(-EINVAL);
>
> - while (e < end) {
> + 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);
> + e_size = le32_to_cpu(e->size);
> + padding_data = le16_to_cpu(e->padding_data);
>
> - if (WARN_ON(e_size > part->size || padding_data > e_size))
> - return ERR_PTR(-EINVAL);
> + if (e_size < part->size && padding_data < e_size)
> + entry_size = e_size - padding_data;
> + else
> + return ERR_PTR(-EINVAL);
>
> - *size = e_size - padding_data;
> - }
> + item_ptr = uncached_entry_to_item(e);
>
> - item_ptr = uncached_entry_to_item(e);
> - if (WARN_ON(item_ptr > p_end))
> + 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;
> }
>
> - e = uncached_entry_next(e);
> - }
> + next_e = uncached_entry_next(e);
> + if (WARN_ON(next_e <= e))
> + return ERR_PTR(-EINVAL);
>
> - if (WARN_ON((void *)e > p_end))
> + e = next_e;
> + }
> + if (WARN_ON((void *)e > (void *)uncached_end))
> return ERR_PTR(-EINVAL);
>
> /* Item was not found in the uncached list, search the cached list */
>
> + if (cached_end == p_end)
> + return ERR_PTR(-ENOENT);
> +
> e = phdr_to_first_cached_entry(phdr, part->cacheline);
> - end = phdr_to_last_cached_entry(phdr);
>
> - if (WARN_ON((void *)e < (void *)phdr || (void *)end > p_end))
> + if (WARN_ON(!IN_PARTITION_RANGE(cached_end, 0, uncached_end, p_end) ||
> + !IN_PARTITION_RANGE(e, sizeof(*e), cached_end, p_end)))
> return ERR_PTR(-EINVAL);
>
> - while (e > end) {
> + while (e > cached_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);
> + e_size = le32_to_cpu(e->size);
> + padding_data = le16_to_cpu(e->padding_data);
>
> - if (WARN_ON(e_size > part->size || padding_data > e_size))
> - return ERR_PTR(-EINVAL);
> -
> - *size = e_size - padding_data;
> - }
> + if (e_size < part->size && padding_data < e_size)
> + entry_size = e_size - padding_data;
> + else
> + return ERR_PTR(-EINVAL);
>
> - item_ptr = cached_entry_to_item(e);
> - if (WARN_ON(item_ptr < (void *)phdr))
> + item_ptr = cached_entry_to_item(e);
> + if (WARN_ON(!IN_PARTITION_RANGE(item_ptr, entry_size, cached_end, e)))
> return ERR_PTR(-EINVAL);
>
> + if (size != NULL)
> + *size = entry_size;
> +
> return item_ptr;
> }
>
> - e = cached_entry_next(e, part->cacheline);
> + next_e = cached_entry_next(e, part->cacheline);
> + if (WARN_ON(next_e >= e))
> + return ERR_PTR(-EINVAL);
> +
> + e = next_e;
> }
>
> if (WARN_ON((void *)e < (void *)phdr))
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] soc: qcom: smem: add boundary checks for partitions
2026-08-31 22:54 ` Bjorn Andersson
@ 2026-09-01 7:04 ` Albert Esteve
0 siblings, 0 replies; 5+ messages in thread
From: Albert Esteve @ 2026-09-01 7:04 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Konrad Dybcio, linux-arm-msm, linux-kernel, Sudeepgoud Patil,
Sarannya S, Pranav Mahesh Phansalkar
On Tue, Sep 1, 2026 at 12:54 AM Bjorn Andersson <andersson@kernel.org> wrote:
>
> On Thu, Aug 20, 2026 at 01:34:18PM +0200, Albert Esteve wrote:
> > From: Sudeepgoud Patil <quic_sudeepgo@quicinc.com>
> >
> > Add condition check to make sure that the end address
> > of private entry does not go out of partition.
> >
> > Signed-off-by: Sarannya S <quic_sarannya@quicinc.com>
> > Signed-off-by: Pranav Mahesh Phansalkar <quic_pphansal@quicinc.com>
> > Signed-off-by: Sudeepgoud Patil <quic_sudeepgo@quicinc.com>
> > Signed-off-by: Albert Esteve <aesteve@redhat.com>
>
> I'm sorry, Albert. Sudeepgoud messed up the authorship vs signed-off-by
> chain here. The author should be "Sarannya", as that's the first
> signed-off-by.
>
> PS. It would also be nice if this was submitted with updated email
> addresses and copyright statement. But I'd not expect you to fix that.
Hi Bjorn,
I'm happy to address these changes for V2. Do you know where to find
the updated email addresses?
BR,
Albert.
>
> Regards,
> Bjorn
>
> > ---
> > drivers/soc/qcom/smem.c | 105 +++++++++++++++++++++++++++++++++---------------
> > 1 file changed, 72 insertions(+), 33 deletions(-)
> >
> > diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
> > index afb21a778fe7b..194ffb2ac010f 100644
> > --- a/drivers/soc/qcom/smem.c
> > +++ b/drivers/soc/qcom/smem.c
> > @@ -2,6 +2,7 @@
> > /*
> > * Copyright (c) 2015, Sony Mobile Communications AB.
> > * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
> > + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
> > */
> >
> > #include <linux/hwspinlock.h>
> > @@ -85,6 +86,17 @@
> > /* Processor/host identifier for the global partition */
> > #define SMEM_GLOBAL_HOST 0xfffe
> >
> > +/* 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
> > @@ -403,6 +415,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;
> > @@ -415,19 +428,25 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
> > end = phdr_to_last_uncached_entry(phdr);
> > cached = phdr_to_last_cached_entry(phdr);
> >
> > - if (WARN_ON((void *)end > p_end || 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)
> > goto bad_canary;
> > if (le16_to_cpu(hdr->item) == item)
> > return -EEXIST;
> >
> > - hdr = uncached_entry_next(hdr);
> > + next_hdr = uncached_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 */
> > @@ -587,9 +606,11 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
> > unsigned item,
> > size_t *size)
> > {
> > - struct smem_private_entry *e, *end;
> > + struct smem_private_entry *e, *uncached_end, *cached_end;
> > + struct smem_private_entry *next_e;
> > struct smem_partition_header *phdr;
> > void *item_ptr, *p_end;
> > + size_t entry_size = 0;
> > u32 padding_data;
> > u32 e_size;
> >
> > @@ -597,67 +618,85 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
> > p_end = (void *)phdr + part->size;
> >
> > e = phdr_to_first_uncached_entry(phdr);
> > - end = phdr_to_last_uncached_entry(phdr);
> > + uncached_end = phdr_to_last_uncached_entry(phdr);
> > + cached_end = phdr_to_last_cached_entry(phdr);
> > +
> > + if (WARN_ON(!IN_PARTITION_RANGE(uncached_end, 0, phdr, cached_end)
> > + || (void *)cached_end > p_end))
> > + return ERR_PTR(-EINVAL);
> >
> > - while (e < end) {
> > + 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);
> > + e_size = le32_to_cpu(e->size);
> > + padding_data = le16_to_cpu(e->padding_data);
> >
> > - if (WARN_ON(e_size > part->size || padding_data > e_size))
> > - return ERR_PTR(-EINVAL);
> > + if (e_size < part->size && padding_data < e_size)
> > + entry_size = e_size - padding_data;
> > + else
> > + return ERR_PTR(-EINVAL);
> >
> > - *size = e_size - padding_data;
> > - }
> > + item_ptr = uncached_entry_to_item(e);
> >
> > - item_ptr = uncached_entry_to_item(e);
> > - if (WARN_ON(item_ptr > p_end))
> > + 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;
> > }
> >
> > - e = uncached_entry_next(e);
> > - }
> > + next_e = uncached_entry_next(e);
> > + if (WARN_ON(next_e <= e))
> > + return ERR_PTR(-EINVAL);
> >
> > - if (WARN_ON((void *)e > p_end))
> > + e = next_e;
> > + }
> > + if (WARN_ON((void *)e > (void *)uncached_end))
> > return ERR_PTR(-EINVAL);
> >
> > /* Item was not found in the uncached list, search the cached list */
> >
> > + if (cached_end == p_end)
> > + return ERR_PTR(-ENOENT);
> > +
> > e = phdr_to_first_cached_entry(phdr, part->cacheline);
> > - end = phdr_to_last_cached_entry(phdr);
> >
> > - if (WARN_ON((void *)e < (void *)phdr || (void *)end > p_end))
> > + if (WARN_ON(!IN_PARTITION_RANGE(cached_end, 0, uncached_end, p_end) ||
> > + !IN_PARTITION_RANGE(e, sizeof(*e), cached_end, p_end)))
> > return ERR_PTR(-EINVAL);
> >
> > - while (e > end) {
> > + while (e > cached_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);
> > + e_size = le32_to_cpu(e->size);
> > + padding_data = le16_to_cpu(e->padding_data);
> >
> > - if (WARN_ON(e_size > part->size || padding_data > e_size))
> > - return ERR_PTR(-EINVAL);
> > -
> > - *size = e_size - padding_data;
> > - }
> > + if (e_size < part->size && padding_data < e_size)
> > + entry_size = e_size - padding_data;
> > + else
> > + return ERR_PTR(-EINVAL);
> >
> > - item_ptr = cached_entry_to_item(e);
> > - if (WARN_ON(item_ptr < (void *)phdr))
> > + item_ptr = cached_entry_to_item(e);
> > + if (WARN_ON(!IN_PARTITION_RANGE(item_ptr, entry_size, cached_end, e)))
> > return ERR_PTR(-EINVAL);
> >
> > + if (size != NULL)
> > + *size = entry_size;
> > +
> > return item_ptr;
> > }
> >
> > - e = cached_entry_next(e, part->cacheline);
> > + next_e = cached_entry_next(e, part->cacheline);
> > + if (WARN_ON(next_e >= e))
> > + return ERR_PTR(-EINVAL);
> > +
> > + e = next_e;
> > }
> >
> > if (WARN_ON((void *)e < (void *)phdr))
> >
> > --
> > 2.55.0
> >
>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-01 7:05 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-20 11:34 [PATCH 0/2] Add automotive SMEM hardening for Qualcomm platforms Albert Esteve
2026-08-20 11:34 ` [PATCH 1/2] soc: qcom: smem: add boundary checks for partitions Albert Esteve
2026-08-31 22:54 ` Bjorn Andersson
2026-09-01 7:04 ` Albert Esteve
2026-08-20 11:34 ` [PATCH 2/2] soc: qcom: smem: ignore multi remote host partitions Albert Esteve
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®