On Mon, Aug 03, 2026 at 05:13:31PM +0530, Mukesh Ojha wrote:
> 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.
>
Fixes: fd2c15ec1dd3 ("remoteproc: resource table overhaul")
Regards,
Bjorn
> Signed-off-by: Mukesh Ojha <[email protected]>
> ---
> include/linux/rsc_table.h | 17 +++++++++++------
> 1 file 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;
> --
> 2.53.0
>