mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 15:41:52 +02:00
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: ba85c644ac ("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>
This commit is contained in:
parent
6d3daa9b8d
commit
3974ea1938
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user