mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2 0/2] Add automotive SMEM hardening for Qualcomm platforms
@ 2026-09-04 15:18 Albert Esteve
  2026-09-04 15:18 ` [PATCH v2 1/2] soc: qcom: smem: add boundary checks for partitions Albert Esteve
  2026-09-04 15:18 ` [PATCH v2 2/2] soc: qcom: smem: ignore multi remote host partitions Albert Esteve
  0 siblings, 2 replies; 6+ messages in thread
From: Albert Esteve @ 2026-09-04 15:18 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio
  Cc: linux-arm-msm, linux-kernel, Albert Esteve, Sarannya S,
	Pranav Mahesh Phansalkar, Sudeepgoud Patil, 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>
---
Changes in v2:
- Update patch 1 authorship to Sarannya
- Update all emails from @quicinc.com to @oss.qualcomm.com
- Make smem.c copyright yearless
- Link to v1: https://lore.kernel.org/r/20260820-port-smem-v1-0-d19a45f583bf@redhat.com

---
Sarannya S (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: bc35965f6940a9bf834d54187b6088b8eb09206d
change-id: 20260819-port-smem-7518c77c9415

Best regards,
-- 
Albert Esteve <aesteve@redhat.com>


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 1/2] soc: qcom: smem: add boundary checks for partitions
  2026-09-04 15:18 [PATCH v2 0/2] Add automotive SMEM hardening for Qualcomm platforms Albert Esteve
@ 2026-09-04 15:18 ` Albert Esteve
  2026-09-23 13:58   ` Konrad Dybcio
  2026-09-04 15:18 ` [PATCH v2 2/2] soc: qcom: smem: ignore multi remote host partitions Albert Esteve
  1 sibling, 1 reply; 6+ messages in thread
From: Albert Esteve @ 2026-09-04 15:18 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio
  Cc: linux-arm-msm, linux-kernel, Albert Esteve, Sarannya S,
	Pranav Mahesh Phansalkar, Sudeepgoud Patil

From: Sarannya S <quic_sarannya@oss.qualcomm.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@oss.qualcomm.com>
Signed-off-by: Pranav Mahesh Phansalkar <quic_pphansal@oss.qualcomm.com>
Signed-off-by: Sudeepgoud Patil <quic_sudeepgo@oss.qualcomm.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 b5e7bd8c1512..1456ff6df293 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) Qualcomm Technologies, Inc. and/or its subsidiaries.
  */
 
 #include <linux/debugfs.h>
@@ -88,6 +89,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
@@ -409,6 +421,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;
@@ -421,19 +434,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 */
@@ -592,9 +611,11 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
 				   unsigned int 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;
 
@@ -602,67 +623,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] 6+ messages in thread

* [PATCH v2 2/2] soc: qcom: smem: ignore multi remote host partitions
  2026-09-04 15:18 [PATCH v2 0/2] Add automotive SMEM hardening for Qualcomm platforms Albert Esteve
  2026-09-04 15:18 ` [PATCH v2 1/2] soc: qcom: smem: add boundary checks for partitions Albert Esteve
@ 2026-09-04 15:18 ` Albert Esteve
  2026-09-23 13:38   ` Konrad Dybcio
  1 sibling, 1 reply; 6+ messages in thread
From: Albert Esteve @ 2026-09-04 15:18 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio
  Cc: linux-arm-msm, linux-kernel, Albert Esteve, Tony Truong

From: Tony Truong <quic_truong@oss.qualcomm.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@oss.qualcomm.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 1456ff6df293..6c59eef6015e 100644
--- a/drivers/soc/qcom/smem.c
+++ b/drivers/soc/qcom/smem.c
@@ -89,6 +89,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
@@ -1091,6 +1094,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] 6+ messages in thread

* Re: [PATCH v2 2/2] soc: qcom: smem: ignore multi remote host partitions
  2026-09-04 15:18 ` [PATCH v2 2/2] soc: qcom: smem: ignore multi remote host partitions Albert Esteve
@ 2026-09-23 13:38   ` Konrad Dybcio
  0 siblings, 0 replies; 6+ messages in thread
From: Konrad Dybcio @ 2026-09-23 13:38 UTC (permalink / raw)
  To: Albert Esteve, Bjorn Andersson, Konrad Dybcio
  Cc: linux-arm-msm, linux-kernel, Tony Truong

On 9/4/26 5:18 PM, Albert Esteve wrote:
> From: Tony Truong <quic_truong@oss.qualcomm.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@oss.qualcomm.com>
> Signed-off-by: Albert Esteve <aesteve@redhat.com>
> ---

Hopefully not for long!

Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>

Konrad

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 1/2] soc: qcom: smem: add boundary checks for partitions
  2026-09-04 15:18 ` [PATCH v2 1/2] soc: qcom: smem: add boundary checks for partitions Albert Esteve
@ 2026-09-23 13:58   ` Konrad Dybcio
  2026-09-23 14:49     ` Albert Esteve
  0 siblings, 1 reply; 6+ messages in thread
From: Konrad Dybcio @ 2026-09-23 13:58 UTC (permalink / raw)
  To: Albert Esteve, Bjorn Andersson, Konrad Dybcio
  Cc: linux-arm-msm, linux-kernel, Sarannya S,
	Pranav Mahesh Phansalkar, Sudeepgoud Patil

On 9/4/26 5:18 PM, Albert Esteve wrote:
> From: Sarannya S <quic_sarannya@oss.qualcomm.com>
> 
> Add condition check to make sure that the end address
> of private entry does not go out of partition.

[...]

> @@ -409,6 +421,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;
> @@ -421,19 +434,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))

strange indentation
>  		return -EINVAL;
>  
> -	while (hdr < end) {
> +	while ((hdr < end) && ((hdr + 1) < end)) {

I believe the latter implies the former

[...]

>  	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))

The || usually goes on the end of the line, please move it there

This patch changes a lot without much explanation, could you please
split it up so that the changes are more focused? I know the general
theme is overflow checks, but a lot of conditions change
simultaneously in its current form and it's hard to track, even GPT
is slightly confused

Konrad

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 1/2] soc: qcom: smem: add boundary checks for partitions
  2026-09-23 13:58   ` Konrad Dybcio
@ 2026-09-23 14:49     ` Albert Esteve
  0 siblings, 0 replies; 6+ messages in thread
From: Albert Esteve @ 2026-09-23 14:49 UTC (permalink / raw)
  To: Konrad Dybcio
  Cc: Bjorn Andersson, Konrad Dybcio, linux-arm-msm, linux-kernel,
	Sarannya S, Pranav Mahesh Phansalkar, Sudeepgoud Patil

On Wed, Sep 23, 2026 at 3:58 PM Konrad Dybcio
<konrad.dybcio@oss.qualcomm.com> wrote:
>
> On 9/4/26 5:18 PM, Albert Esteve wrote:
> > From: Sarannya S <quic_sarannya@oss.qualcomm.com>
> >
> > Add condition check to make sure that the end address
> > of private entry does not go out of partition.
>
> [...]
>
> > @@ -409,6 +421,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;
> > @@ -421,19 +434,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))
>
> strange indentation
> >               return -EINVAL;
> >
> > -     while (hdr < end) {
> > +     while ((hdr < end) && ((hdr + 1) < end)) {
>
> I believe the latter implies the former

Yes, the check that matter is the second part. I'll fix it in the next
version, thanks!

>
> [...]
>
> >       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))
>
> The || usually goes on the end of the line, please move it there
>
> This patch changes a lot without much explanation, could you please
> split it up so that the changes are more focused? I know the general
> theme is overflow checks, but a lot of conditions change
> simultaneously in its current form and it's hard to track, even GPT
> is slightly confused

Yeah, you're right. I was preserving the original patch as is, but I
will try to split it in a way that makes sense, while keeping the
original SoBs.

BR,
Albert

>
> Konrad
>


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-09-23 14:50 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-04 15:18 [PATCH v2 0/2] Add automotive SMEM hardening for Qualcomm platforms Albert Esteve
2026-09-04 15:18 ` [PATCH v2 1/2] soc: qcom: smem: add boundary checks for partitions Albert Esteve
2026-09-23 13:58   ` Konrad Dybcio
2026-09-23 14:49     ` Albert Esteve
2026-09-04 15:18 ` [PATCH v2 2/2] soc: qcom: smem: ignore multi remote host partitions Albert Esteve
2026-09-23 13:38   ` Konrad Dybcio

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®