]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
firmware: arm_ffa: Fix out-of-bound writes in ffa_setup_and_transmit()
authorMostafa Saleh <smostafa@google.com>
Thu, 2 Jul 2026 10:38:38 +0000 (10:38 +0000)
committerMarc Zyngier <maz@kernel.org>
Tue, 7 Jul 2026 14:04:07 +0000 (15:04 +0100)
Sashiko (locally) reports multiple out-of-bound issues in
ffa_setup_and_transmit:
1) Writing ep_mem_access->reserved can write out of bounds for FFA
   versions < 1.2 as ffa_emad_size_get() returns 16 bytes in that case
   while reserved has an offset of 24.
   Instead of zeroing fields, memset the struct to zero first based on
   the FFA version.

2) Make sure there is enough size to write constituents.

While at it, convert the only sizeof() in the driver that uses a
type instead of variable.

Reviewed-by: Sudeep Holla <sudeep.holla@kernel.org>
Fixes: 111a833dc5cb ("firmware: arm_ffa: Set reserved/MBZ fields to zero in the memory descriptors")
Signed-off-by: Mostafa Saleh <smostafa@google.com>
Signed-off-by: Sebastian Ene <sebastianene@google.com>
Link: https://patch.msgid.link/20260702103848.1647249-2-sebastianene@google.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
drivers/firmware/arm_ffa/driver.c

index eb2782848283762a74d9c4fe72339c29a111819b..b700b2e93e72105c5e39dffa44a087bfd48d607e 100644 (file)
@@ -697,11 +697,10 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
        for (idx = 0; idx < args->nattrs; idx++) {
                ep_mem_access = buffer +
                        ffa_mem_desc_offset(buffer, idx, drv_info->version);
+               memset(ep_mem_access, 0, ffa_emad_size_get(drv_info->version));
                ep_mem_access->receiver = args->attrs[idx].receiver;
                ep_mem_access->attrs = args->attrs[idx].attrs;
                ep_mem_access->composite_off = composite_offset;
-               ep_mem_access->flag = 0;
-               ep_mem_access->reserved = 0;
                ffa_emad_impdef_value_init(drv_info->version,
                                           ep_mem_access->impdef_val,
                                           args->attrs[idx].impdef_val);
@@ -741,7 +740,7 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
                        constituents = buffer;
                }
 
-               if ((void *)constituents - buffer > max_fragsize) {
+               if ((void *)constituents + sizeof(*constituents) - buffer > max_fragsize) {
                        pr_err("Memory Region Fragment > Tx Buffer size\n");
                        return -EFAULT;
                }
@@ -750,7 +749,7 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
                constituents->pg_cnt = args->sg->length / FFA_PAGE_SIZE;
                constituents->reserved = 0;
                constituents++;
-               frag_len += sizeof(struct ffa_mem_region_addr_range);
+               frag_len += sizeof(*constituents);
        } while ((args->sg = sg_next(args->sg)));
 
        return ffa_transmit_fragment(func_id, addr, buf_sz, frag_len,