[PATCH] soc: qcom: cmd-db: Validate firmware-provided offsets and counts

From: Krzysztof Kozlowski

Date: Wed Nov 04 2026 - 11:32:43 EST


Validate the data provided by the firmware, before actually trusting
declared lengths and parsing it. If a theoretical firmware provided
malformed data, Linux kernel could read beyond allocated reserved
memory.

Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
Closes: https://sashiko.dev/#/bug/linux-fc833525-3bf9-4274-8dc7-2cffd5b4338c
Fixes: 312416d9171a ("drivers: qcom: add command DB driver")
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@xxxxxxxxxxxxxxxx>

---

Not ccing stable, this is a theoretical bug.
---
drivers/soc/qcom/cmd-db.c | 50 +++++++++++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)

diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c
index 5d303ca0dbd0..c75567cea086 100644
--- a/drivers/soc/qcom/cmd-db.c
+++ b/drivers/soc/qcom/cmd-db.c
@@ -338,10 +338,51 @@ static const struct file_operations cmd_db_debugfs_ops = {
.release = single_release,
};

+static int cmd_db_validate(struct device *dev,
+ const struct cmd_db_header *header, size_t size)
+{
+ const struct entry_header *ent;
+ const struct rsc_hdr *rsc;
+ size_t data_size, end;
+ u16 cnt;
+ int i, j;
+
+ data_size = size - sizeof(*header);
+
+ for (i = 0; i < MAX_SLV_ID; i++) {
+ rsc = &header->header[i];
+ if (!rsc->slv_id)
+ break;
+
+ cnt = le16_to_cpu(rsc->cnt);
+ end = le16_to_cpu(rsc->header_offset) +
+ (size_t)cnt * sizeof(*ent);
+ if (end > data_size) {
+ dev_err(dev, "Slave %d entries out of bounds\n", i);
+ return -EINVAL;
+ }
+
+ ent = (const void *)(header->data +
+ le16_to_cpu(rsc->header_offset));
+ for (j = 0; j < cnt; j++, ent++) {
+ end = (size_t)le16_to_cpu(rsc->data_offset) +
+ le16_to_cpu(ent->offset) + le16_to_cpu(ent->len);
+ if (end > data_size) {
+ dev_err(dev, "Slave %d entry %d data out of bounds\n",
+ i, j);
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
static int cmd_db_dev_probe(struct platform_device *pdev)
{
struct cmd_db_header *header;
struct reserved_mem *rmem;
+ int ret;

rmem = of_reserved_mem_lookup(pdev->dev.of_node);
if (!rmem) {
@@ -349,6 +390,11 @@ static int cmd_db_dev_probe(struct platform_device *pdev)
return -EINVAL;
}

+ if (rmem->size < sizeof(*header)) {
+ dev_err(&pdev->dev, "Command DB memory region too small\n");
+ return -EINVAL;
+ }
+
header = devm_memremap(&pdev->dev, rmem->base, rmem->size, MEMREMAP_WC);
if (IS_ERR(header))
return PTR_ERR(header);
@@ -358,6 +404,10 @@ static int cmd_db_dev_probe(struct platform_device *pdev)
return -EINVAL;
}

+ ret = cmd_db_validate(&pdev->dev, header, rmem->size);
+ if (ret)
+ return ret;
+
cmd_db_header = header;

debugfs_create_file("cmd-db", 0400, NULL, NULL, &cmd_db_debugfs_ops);
--
2.53.0