diff options
| author | Mukesh Ojha <mukesh.ojha@oss.qualcomm.com> | 2026-08-03 17:13:31 +0530 |
|---|---|---|
| committer | Bjorn Andersson <andersson@kernel.org> | 2026-08-04 17:32:02 -0500 |
| commit | bb840ea69347aff7bde5a208e7b5b180669a7656 (patch) | |
| tree | 6625c1cf5f69dbcc3cdd0d2c09ed2a4018aeee81 | |
| parent | bf9053b22ccbb4d481135d0000fac7302d060af0 (diff) | |
| download | linux-next-bb840ea69347aff7bde5a208e7b5b180669a7656.tar.gz linux-next-bb840ea69347aff7bde5a208e7b5b180669a7656.zip | |
remoteproc: fix OOB read via signed offset in rsc_table_for_each_entry()
table->offset[i] is a u32 from firmware, but was stored into a signed
int. A crafted offset like 0xFFFFFFF0 becomes -16, placing hdr 16 bytes
before the table buffer. The subsequent avail check was bypassed
because the negative int was promoted to a large size_t in the
expression "table_sz - offset - sizeof(*hdr)", yielding a large positive
avail and letting the out-of-bounds hdr->type read proceed undetected.
Store the offset as u32 and validate it with unsigned comparisons before
any pointer arithmetic.
Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
Fixes: fd2c15ec1dd3 ("remoteproc: resource table overhaul")
Link: https://lore.kernel.org/r/20260803114331.3277263-6-mukesh.ojha@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
| -rw-r--r-- | include/linux/rsc_table.h | 17 |
1 files changed, 11 insertions, 6 deletions
diff --git a/include/linux/rsc_table.h b/include/linux/rsc_table.h index 0ad9122c22af..71b60125310e 100644 --- a/include/linux/rsc_table.h +++ b/include/linux/rsc_table.h @@ -310,17 +310,22 @@ static inline int rsc_table_for_each_entry(struct resource_table *table, int i, ret; for (i = 0; i < table->num; i++) { - int offset = table->offset[i]; - struct fw_rsc_hdr *hdr = (void *)table + offset; - int avail = table_sz - offset - sizeof(*hdr); - int rsc_offset = offset + sizeof(*hdr); - void *rsc = (void *)hdr + sizeof(*hdr); + u32 offset = table->offset[i]; + struct fw_rsc_hdr *hdr; + int avail, rsc_offset; + void *rsc; - if (avail < 0) { + if (offset < sizeof(*table) || offset >= table_sz || + table_sz - offset < sizeof(*hdr)) { dev_err(dev, "rsc table is truncated\n"); return -EINVAL; } + hdr = (void *)table + offset; + avail = table_sz - offset - sizeof(*hdr); + rsc_offset = offset + sizeof(*hdr); + rsc = (void *)hdr + sizeof(*hdr); + ret = cb(hdr->type, rsc, rsc_offset, avail, data); if (ret) return ret; |
