]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
firmware: arm_ffa: Fix Endpoint Memory Access Descriptor offset calculation
authorSebastian Ene <sebastianene@google.com>
Thu, 2 Jul 2026 10:38:39 +0000 (10:38 +0000)
committerMarc Zyngier <maz@kernel.org>
Tue, 7 Jul 2026 14:04:07 +0000 (15:04 +0100)
Use the descriptor's `ep_mem_offset` to calculate the start of the endpoint
memory access array and to comply with the FF-A spec instead of defaulting
to `sizeof(struct ffa_mem_region)`.
This requires moving `ffa_mem_region_additional_setup()` earlier in the setup
flow.
Also, add sanity checks to ensure the calculated descriptor offsets do not
exceed `max_fragsize`.

Fixes: 113580530ee7 ("firmware: arm_ffa: Update memory descriptor to support v1.1 format")
Reviewed-by: Sudeep Holla <sudeep.holla@kernel.org>
Signed-off-by: Mostafa Saleh <smostafa@google.com>
Signed-off-by: Sebastian Ene <sebastianene@google.com>
Link: https://patch.msgid.link/20260702103848.1647249-3-sebastianene@google.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
drivers/firmware/arm_ffa/driver.c
include/linux/arm_ffa.h

index b700b2e93e72105c5e39dffa44a087bfd48d607e..0ad323decada75520dc5a0304744b8c3f828b294 100644 (file)
@@ -685,19 +685,30 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
        struct ffa_composite_mem_region *composite;
        struct ffa_mem_region_addr_range *constituents;
        struct ffa_mem_region_attributes *ep_mem_access;
-       u32 idx, frag_len, length, buf_sz = 0, num_entries = sg_nents(args->sg);
+       u32 idx, frag_len, length, buf_sz = 0, num_entries = sg_nents(args->sg), ep_offset;
+       u32 emad_end, emad_size = ffa_emad_size_get(drv_info->version);
 
        mem_region->tag = args->tag;
        mem_region->flags = args->flags;
        mem_region->sender_id = drv_info->vm_id;
        mem_region->attributes = ffa_memory_attributes_get(func_id);
+
+       ffa_mem_region_additional_setup(drv_info->version, mem_region);
        composite_offset = ffa_mem_desc_offset(buffer, args->nattrs,
                                               drv_info->version);
+       if (composite_offset + sizeof(*composite) > max_fragsize)
+               return -ENXIO;
 
        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_offset = ffa_mem_desc_offset(buffer, idx, drv_info->version);
+               if (check_add_overflow(ep_offset, emad_size, &emad_end))
+                       return -ENXIO;
+
+               if (emad_end > max_fragsize)
+                       return -ENXIO;
+
+               ep_mem_access = buffer + ep_offset;
+               memset(ep_mem_access, 0, emad_size);
                ep_mem_access->receiver = args->attrs[idx].receiver;
                ep_mem_access->attrs = args->attrs[idx].attrs;
                ep_mem_access->composite_off = composite_offset;
@@ -707,7 +718,6 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
        }
        mem_region->handle = 0;
        mem_region->ep_count = args->nattrs;
-       ffa_mem_region_additional_setup(drv_info->version, mem_region);
 
        composite = buffer + composite_offset;
        composite->total_pg_cnt = ffa_get_num_pages_sg(args->sg);
index 3c91d4c4153c5011f00f71483ef58a4e358d15cc..c6a9ffd564f7479f168c12a1309c0545ba104219 100644 (file)
@@ -452,7 +452,7 @@ ffa_mem_desc_offset(struct ffa_mem_region *buf, int count, u32 ffa_version)
        if (!FFA_MEM_REGION_HAS_EP_MEM_OFFSET(ffa_version))
                offset += offsetof(struct ffa_mem_region, ep_mem_offset);
        else
-               offset += sizeof(struct ffa_mem_region);
+               offset += buf->ep_mem_offset;
 
        return offset;
 }