Skip to content

Commit 227c340

Browse files
Sudeep HollajamieNguyenNVIDIA
authored andcommitted
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> (cherry picked from commit 3974ea1) Signed-off-by: Jamie Nguyen <jamien@nvidia.com>
1 parent 42cad5f commit 227c340

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
@@ -318,22 +318,26 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
318318
#define PART_INFO_ID_MASK GENMASK(15, 0)
319319
#define PART_INFO_EXEC_CXT_MASK GENMASK(31, 16)
320320
#define PART_INFO_PROPS_MASK GENMASK(63, 32)
321+
#define FFA_PART_INFO_GET_REGS_FIRST_REG 3
322+
#define FFA_PART_INFO_GET_REGS_REGS_PER_DESC 3
323+
#define FFA_PART_INFO_GET_REGS_MAX_DESC \
324+
(((sizeof(ffa_value_t) / sizeof_field(ffa_value_t, a0)) - \
325+
FFA_PART_INFO_GET_REGS_FIRST_REG) / \
326+
FFA_PART_INFO_GET_REGS_REGS_PER_DESC)
321327
#define PART_INFO_ID(x) ((u16)(FIELD_GET(PART_INFO_ID_MASK, (x))))
322328
#define PART_INFO_EXEC_CXT(x) ((u16)(FIELD_GET(PART_INFO_EXEC_CXT_MASK, (x))))
323329
#define PART_INFO_PROPERTIES(x) ((u32)(FIELD_GET(PART_INFO_PROPS_MASK, (x))))
324330
static int
325331
__ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
326332
struct ffa_partition_info *buffer, int num_parts)
327333
{
328-
u16 buf_sz, start_idx, cur_idx, count = 0, prev_idx = 0, tag = 0;
334+
u16 buf_sz, start_idx = 0, cur_idx, count = 0, tag = 0;
329335
struct ffa_partition_info *buf = buffer;
330336
ffa_value_t partition_info;
331337

332338
do {
333339
__le64 *regs;
334-
int idx;
335-
336-
start_idx = prev_idx ? prev_idx + 1 : 0;
340+
int idx, nr_desc, buf_idx;
337341

338342
invoke_ffa_fn((ffa_value_t){
339343
.a0 = FFA_PARTITION_INFO_GET_REGS,
@@ -349,15 +353,28 @@ __ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
349353
count = PARTITION_COUNT(partition_info.a2);
350354
if (!buffer || !num_parts) /* count only */
351355
return count;
356+
if (count > num_parts)
357+
return -EINVAL;
352358

353359
cur_idx = CURRENT_INDEX(partition_info.a2);
360+
if (cur_idx < start_idx || cur_idx >= count)
361+
return -EINVAL;
362+
363+
nr_desc = cur_idx - start_idx + 1;
364+
if (nr_desc > FFA_PART_INFO_GET_REGS_MAX_DESC)
365+
return -EINVAL;
366+
367+
buf_idx = buf - buffer;
368+
if (buf_idx + nr_desc > num_parts)
369+
return -EINVAL;
370+
354371
tag = UUID_INFO_TAG(partition_info.a2);
355372
buf_sz = PARTITION_INFO_SZ(partition_info.a2);
356373
if (buf_sz > sizeof(*buffer))
357374
buf_sz = sizeof(*buffer);
358375

359376
regs = (void *)&partition_info.a3;
360-
for (idx = 0; idx < cur_idx - start_idx + 1; idx++, buf++) {
377+
for (idx = 0; idx < nr_desc; idx++, buf++) {
361378
union {
362379
uuid_t uuid;
363380
u64 regs[2];
@@ -375,7 +392,7 @@ __ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
375392
uuid_copy(&buf->uuid, &uuid_regs.uuid);
376393
regs += 3;
377394
}
378-
prev_idx = cur_idx;
395+
start_idx = cur_idx + 1;
379396

380397
} while (cur_idx < (count - 1));
381398

0 commit comments

Comments
 (0)