]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
firmware: arm_ffa: Bound PARTITION_INFO_GET_REGS copies
authorSudeep Holla <sudeep.holla@kernel.org>
Tue, 28 Apr 2026 18:33:30 +0000 (19:33 +0100)
committerSudeep Holla <sudeep.holla@kernel.org>
Tue, 5 May 2026 15:40:41 +0000 (16:40 +0100)
The register-based PARTITION_INFO_GET path trusted the firmware-provided
indices when copying partition descriptors into the caller buffer.
Reject inconsistent counts or index progressions so the copy loop cannot
write past the allocated array.

Fixes: ba85c644ac8d ("firmware: arm_ffa: Add support for FFA_PARTITION_INFO_GET_REGS")
Link: https://patch.msgid.link/20260428-ffa_fixes-v2-6-8595ae450034@kernel.org
(fixed cur_idx when exactly one descriptor in the first fragment)
Signed-off-by: Sudeep Holla <sudeep.holla@kernel.org>
drivers/firmware/arm_ffa/driver.c

index a122814eb6d75edff3bb68dd1209598b4057dfd9..33b417e78684de267d32833a8f51c303b3d34b69 100644 (file)
@@ -323,6 +323,12 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
 #define PART_INFO_ID_MASK      GENMASK(15, 0)
 #define PART_INFO_EXEC_CXT_MASK        GENMASK(31, 16)
 #define PART_INFO_PROPS_MASK   GENMASK(63, 32)
+#define FFA_PART_INFO_GET_REGS_FIRST_REG       3
+#define FFA_PART_INFO_GET_REGS_REGS_PER_DESC   3
+#define FFA_PART_INFO_GET_REGS_MAX_DESC \
+       (((sizeof(ffa_value_t) / sizeof_field(ffa_value_t, a0)) - \
+         FFA_PART_INFO_GET_REGS_FIRST_REG) / \
+        FFA_PART_INFO_GET_REGS_REGS_PER_DESC)
 #define PART_INFO_ID(x)                ((u16)(FIELD_GET(PART_INFO_ID_MASK, (x))))
 #define PART_INFO_EXEC_CXT(x)  ((u16)(FIELD_GET(PART_INFO_EXEC_CXT_MASK, (x))))
 #define PART_INFO_PROPERTIES(x)        ((u32)(FIELD_GET(PART_INFO_PROPS_MASK, (x))))
@@ -330,15 +336,13 @@ static int
 __ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
                              struct ffa_partition_info *buffer, int num_parts)
 {
-       u16 buf_sz, start_idx, cur_idx, count = 0, prev_idx = 0, tag = 0;
+       u16 buf_sz, start_idx = 0, cur_idx, count = 0, tag = 0;
        struct ffa_partition_info *buf = buffer;
        ffa_value_t partition_info;
 
        do {
                __le64 *regs;
-               int idx;
-
-               start_idx = prev_idx ? prev_idx + 1 : 0;
+               int idx, nr_desc, buf_idx;
 
                invoke_ffa_fn((ffa_value_t){
                              .a0 = FFA_PARTITION_INFO_GET_REGS,
@@ -354,15 +358,28 @@ __ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
                        count = PARTITION_COUNT(partition_info.a2);
                if (!buffer || !num_parts) /* count only */
                        return count;
+               if (count > num_parts)
+                       return -EINVAL;
 
                cur_idx = CURRENT_INDEX(partition_info.a2);
+               if (cur_idx < start_idx || cur_idx >= count)
+                       return -EINVAL;
+
+               nr_desc = cur_idx - start_idx + 1;
+               if (nr_desc > FFA_PART_INFO_GET_REGS_MAX_DESC)
+                       return -EINVAL;
+
+               buf_idx = buf - buffer;
+               if (buf_idx + nr_desc > num_parts)
+                       return -EINVAL;
+
                tag = UUID_INFO_TAG(partition_info.a2);
                buf_sz = PARTITION_INFO_SZ(partition_info.a2);
                if (buf_sz > sizeof(*buffer))
                        buf_sz = sizeof(*buffer);
 
                regs = (void *)&partition_info.a3;
-               for (idx = 0; idx < cur_idx - start_idx + 1; idx++, buf++) {
+               for (idx = 0; idx < nr_desc; idx++, buf++) {
                        union {
                                uuid_t uuid;
                                u64 regs[2];
@@ -380,7 +397,7 @@ __ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
                        uuid_copy(&buf->uuid, &uuid_regs.uuid);
                        regs += 3;
                }
-               prev_idx = cur_idx;
+               start_idx = cur_idx + 1;
 
        } while (cur_idx < (count - 1));