Skip to content

Commit ebf2be6

Browse files
Sudeep Hollajacobmartin0
authored andcommitted
firmware: arm_ffa: Bound PARTITION_INFO_GET_REGS copies
BugLink: https://bugs.launchpad.net/bugs/2154045 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> Acked-by: Nirmoy Das <nirmoyd@nvidia.com> Acked-by: Seth Forshee <sforshee@nvidia.com> Acked-by: Carol L Soto <csoto@nvidia.com> Signed-off-by: Brad Figg <bfigg@nvidia.com>
1 parent 978bfcc commit ebf2be6

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
@@ -322,22 +322,26 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
322322
#define PART_INFO_ID_MASK GENMASK(15, 0)
323323
#define PART_INFO_EXEC_CXT_MASK GENMASK(31, 16)
324324
#define PART_INFO_PROPS_MASK GENMASK(63, 32)
325+
#define FFA_PART_INFO_GET_REGS_FIRST_REG 3
326+
#define FFA_PART_INFO_GET_REGS_REGS_PER_DESC 3
327+
#define FFA_PART_INFO_GET_REGS_MAX_DESC \
328+
(((sizeof(ffa_value_t) / sizeof_field(ffa_value_t, a0)) - \
329+
FFA_PART_INFO_GET_REGS_FIRST_REG) / \
330+
FFA_PART_INFO_GET_REGS_REGS_PER_DESC)
325331
#define PART_INFO_ID(x) ((u16)(FIELD_GET(PART_INFO_ID_MASK, (x))))
326332
#define PART_INFO_EXEC_CXT(x) ((u16)(FIELD_GET(PART_INFO_EXEC_CXT_MASK, (x))))
327333
#define PART_INFO_PROPERTIES(x) ((u32)(FIELD_GET(PART_INFO_PROPS_MASK, (x))))
328334
static int
329335
__ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
330336
struct ffa_partition_info *buffer, int num_parts)
331337
{
332-
u16 buf_sz, start_idx, cur_idx, count = 0, prev_idx = 0, tag = 0;
338+
u16 buf_sz, start_idx = 0, cur_idx, count = 0, tag = 0;
333339
struct ffa_partition_info *buf = buffer;
334340
ffa_value_t partition_info;
335341

336342
do {
337343
__le64 *regs;
338-
int idx;
339-
340-
start_idx = prev_idx ? prev_idx + 1 : 0;
344+
int idx, nr_desc, buf_idx;
341345

342346
invoke_ffa_fn((ffa_value_t){
343347
.a0 = FFA_PARTITION_INFO_GET_REGS,
@@ -353,15 +357,28 @@ __ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
353357
count = PARTITION_COUNT(partition_info.a2);
354358
if (!buffer || !num_parts) /* count only */
355359
return count;
360+
if (count > num_parts)
361+
return -EINVAL;
356362

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

363380
regs = (void *)&partition_info.a3;
364-
for (idx = 0; idx < cur_idx - start_idx + 1; idx++, buf++) {
381+
for (idx = 0; idx < nr_desc; idx++, buf++) {
365382
union {
366383
uuid_t uuid;
367384
u64 regs[2];
@@ -379,7 +396,7 @@ __ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
379396
uuid_copy(&buf->uuid, &uuid_regs.uuid);
380397
regs += 3;
381398
}
382-
prev_idx = cur_idx;
399+
start_idx = cur_idx + 1;
383400

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

0 commit comments

Comments
 (0)