remoteproc: qcom: Fix minidump out-of-bounds access on subsystems array

MAX_NUM_OF_SS was hardcoded to 10 in the minidump_global_toc struct,
which is a direct overlay on an SMEM item allocated by the firmware.
Newer Qualcomm SoC firmware allocates space for more subsystems, while
older firmware only allocates space for 10. Bumping the constant would
cause Linux to read/write beyond the SMEM item boundary on older
platforms.

Fix this by converting subsystems[] to a flexible array member and
deriving the actual number of subsystems at runtime from the size
returned by qcom_smem_get(). Add a bounds check on minidump_id against
the derived count before indexing into the array.

Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
Acked-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260331171243.1962067-1-mukesh.ojha@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
This commit is contained in:
Mukesh Ojha authored and Bjorn Andersson committed 2026-04-06 09:44:12 -05:00
1 parent 479ba9d293
commit 743cfae79d
1 file changed
+14 -3
+14 -3
View File
@@ -28,7 +28,6 @@
#define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev)
#define to_pdm_subdev(d) container_of(d, struct qcom_rproc_pdm, subdev)
#define MAX_NUM_OF_SS 10
#define MAX_REGION_NAME_LENGTH 16
#define SBL_MINIDUMP_SMEM_ID 602
#define MINIDUMP_REGION_VALID ('V' << 24 | 'A' << 16 | 'L' << 8 | 'I' << 0)
@@ -80,7 +79,7 @@ struct minidump_global_toc {
__le32 status;
__le32 md_revision;
__le32 enabled;
struct minidump_subsystem subsystems[MAX_NUM_OF_SS];
struct minidump_subsystem subsystems[];
};
struct qcom_ssr_subsystem {
@@ -151,9 +150,11 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id,
int ret;
struct minidump_subsystem *subsystem;
struct minidump_global_toc *toc;
unsigned int num_ss;
size_t toc_size;
/* Get Global minidump ToC*/
toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, NULL);
toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, &toc_size);
/* check if global table pointer exists and init is set */
if (IS_ERR(toc) || !toc->status) {
@@ -161,6 +162,16 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id,
return;
}
/* Derive the number of subsystems from the actual SMEM item size */
num_ss = (toc_size - offsetof(struct minidump_global_toc, subsystems)) /
sizeof(struct minidump_subsystem);
if (minidump_id >= num_ss) {
dev_err(&rproc->dev, "Minidump id %d is out of range: %d\n",
minidump_id, num_ss);
return;
}
/* Get subsystem table of contents using the minidump id */
subsystem = &toc->subsystems[minidump_id];