Skip to content

Commit 3974ea1

Browse files
author
Sudeep Holla
committed
firmware: arm_ffa: Bound PARTITION_INFO_GET_REGS copies
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: ba85c64 ("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>
1 parent 6d3daa9 commit 3974ea1

1 file changed

Lines changed: 23 additions & 6 deletions

File tree

drivers/firmware/arm_ffa/driver.c

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -323,22 +323,26 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
323323
#define PART_INFO_ID_MASK GENMASK(15, 0)
324324
#define PART_INFO_EXEC_CXT_MASK GENMASK(31, 16)
325325
#define PART_INFO_PROPS_MASK GENMASK(63, 32)
326+
#define FFA_PART_INFO_GET_REGS_FIRST_REG 3
327+
#define FFA_PART_INFO_GET_REGS_REGS_PER_DESC 3
328+
#define FFA_PART_INFO_GET_REGS_MAX_DESC \
329+
(((sizeof(ffa_value_t) / sizeof_field(ffa_value_t, a0)) - \
330+
FFA_PART_INFO_GET_REGS_FIRST_REG) / \
331+
FFA_PART_INFO_GET_REGS_REGS_PER_DESC)
326332
#define PART_INFO_ID(x) ((u16)(FIELD_GET(PART_INFO_ID_MASK, (x))))
327333
#define PART_INFO_EXEC_CXT(x) ((u16)(FIELD_GET(PART_INFO_EXEC_CXT_MASK, (x))))
328334
#define PART_INFO_PROPERTIES(x) ((u32)(FIELD_GET(PART_INFO_PROPS_MASK, (x))))
329335
static int
330336
__ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
331337
struct ffa_partition_info *buffer, int num_parts)
332338
{
333-
u16 buf_sz, start_idx, cur_idx, count = 0, prev_idx = 0, tag = 0;
339+
u16 buf_sz, start_idx = 0, cur_idx, count = 0, tag = 0;
334340
struct ffa_partition_info *buf = buffer;
335341
ffa_value_t partition_info;
336342

337343
do {
338344
__le64 *regs;
339-
int idx;
340-
341-
start_idx = prev_idx ? prev_idx + 1 : 0;
345+
int idx, nr_desc, buf_idx;
342346

343347
invoke_ffa_fn((ffa_value_t){
344348
.a0 = FFA_PARTITION_INFO_GET_REGS,
@@ -354,15 +358,28 @@ __ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
354358
count = PARTITION_COUNT(partition_info.a2);
355359
if (!buffer || !num_parts) /* count only */
356360
return count;
361+
if (count > num_parts)
362+
return -EINVAL;
357363

358364
cur_idx = CURRENT_INDEX(partition_info.a2);
365+
if (cur_idx < start_idx || cur_idx >= count)
366+
return -EINVAL;
367+
368+
nr_desc = cur_idx - start_idx + 1;
369+
if (nr_desc > FFA_PART_INFO_GET_REGS_MAX_DESC)
370+
return -EINVAL;
371+
372+
buf_idx = buf - buffer;
373+
if (buf_idx + nr_desc > num_parts)
374+
return -EINVAL;
375+
359376
tag = UUID_INFO_TAG(partition_info.a2);
360377
buf_sz = PARTITION_INFO_SZ(partition_info.a2);
361378
if (buf_sz > sizeof(*buffer))
362379
buf_sz = sizeof(*buffer);
363380

364381
regs = (void *)&partition_info.a3;
365-
for (idx = 0; idx < cur_idx - start_idx + 1; idx++, buf++) {
382+
for (idx = 0; idx < nr_desc; idx++, buf++) {
366383
union {
367384
uuid_t uuid;
368385
u64 regs[2];
@@ -380,7 +397,7 @@ __ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
380397
uuid_copy(&buf->uuid, &uuid_regs.uuid);
381398
regs += 3;
382399
}
383-
prev_idx = cur_idx;
400+
start_idx = cur_idx + 1;
384401

385402
} while (cur_idx < (count - 1));
386403

0 commit comments

Comments
 (0)