fix(ff-a): fix MTE issue in ffa_partition_info_get
Previously versioned_partition_info used in the memcpy pointed to
a variable decalared in a scope that no longer existed causing a
use after free fault. Move the memcpy into the scope to prevent this.
Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>
Change-Id: I906dfe142f1e156c5895924f66f0151464ce7a8f
diff --git a/src/api.c b/src/api.c
index 67900b4..c80b701 100644
--- a/src/api.c
+++ b/src/api.c
@@ -363,72 +363,68 @@
* by the endpoint and return the size of the array created.
*/
static struct ffa_value send_versioned_partition_info_descriptors(
- struct vm *current_vm, struct ffa_partition_info *partitions,
+ struct vm_locked vm_locked, struct ffa_partition_info *partitions,
uint32_t vm_count)
{
- struct vm_locked current_vm_locked;
- uint32_t version = current_vm->ffa_version;
- void *versioned_partition_info;
+ struct vm *vm = vm_locked.vm;
+ uint32_t version = vm->ffa_version;
uint32_t size;
- struct ffa_value ret;
- if (version == MAKE_FFA_VERSION(1, 0)) {
- struct ffa_partition_info_v1_0 v1_0_partitions[2 * MAX_VMS];
-
- for (uint32_t i = 0; i < vm_count; i++) {
- v1_0_partitions[i].vm_id = partitions[i].vm_id;
- v1_0_partitions[i].vcpu_count =
- partitions[i].vcpu_count;
- v1_0_partitions[i].properties =
- partitions[i].properties;
- }
- versioned_partition_info = v1_0_partitions;
- size = sizeof(v1_0_partitions[0]) * vm_count;
- } else {
- versioned_partition_info = partitions;
- size = sizeof(partitions[0]) * vm_count;
- }
-
- if (size > FFA_MSG_PAYLOAD_MAX) {
- dlog_error(
- "Partition information does not fit in the VM's RX "
- "buffer.\n");
- return ffa_error(FFA_NO_MEMORY);
- }
-
- /*
- * Partition information is returned in the VM's RX buffer, which is why
- * the lock is needed.
- */
- current_vm_locked = vm_lock(current_vm);
-
- if (msg_receiver_busy(current_vm_locked, NULL, false)) {
+ if (msg_receiver_busy(vm_locked, NULL, false)) {
/*
* Can't retrieve memory information if the mailbox is not
* available.
*/
dlog_verbose("RX buffer not ready.\n");
- ret = ffa_error(FFA_BUSY);
- goto out_unlock;
+ return ffa_error(FFA_BUSY);
}
- /* Populate the VM's RX buffer with the partition information. */
- memcpy_s(current_vm->mailbox.recv, FFA_MSG_PAYLOAD_MAX,
- versioned_partition_info, size);
- current_vm->mailbox.recv_size = size;
+ if (version == MAKE_FFA_VERSION(1, 0)) {
+ struct ffa_partition_info_v1_0 *recv_mailbox = vm->mailbox.recv;
+
+ size = sizeof(struct ffa_partition_info_v1_0) * vm_count;
+ if (size > HF_MAILBOX_SIZE) {
+ dlog_error(
+ "Partition information does not fit in the "
+ "VM's RX "
+ "buffer.\n");
+ return ffa_error(FFA_NO_MEMORY);
+ }
+
+ for (uint32_t i = 0; i < vm_count; i++) {
+ /*
+ * Populate the VM's RX buffer with the partition
+ * information.
+ */
+ recv_mailbox[i].vm_id = partitions[i].vm_id;
+ recv_mailbox[i].vcpu_count = partitions[i].vcpu_count;
+ recv_mailbox[i].properties = partitions[i].properties;
+ }
+
+ } else {
+ size = sizeof(partitions[0]) * vm_count;
+ if (size > HF_MAILBOX_SIZE) {
+ dlog_error(
+ "Partition information does not fit in the "
+ "VM's RX "
+ "buffer.\n");
+ return ffa_error(FFA_NO_MEMORY);
+ }
+
+ /* Populate the VM's RX buffer with the partition information.
+ */
+ memcpy_s(vm->mailbox.recv, HF_MAILBOX_SIZE, partitions, size);
+ }
+
+ vm->mailbox.recv_size = size;
/* Sender is Hypervisor in the normal world (TEE in secure world). */
- current_vm->mailbox.recv_sender = HF_VM_ID_BASE;
- current_vm->mailbox.recv_func = FFA_PARTITION_INFO_GET_32;
- current_vm->mailbox.state = MAILBOX_STATE_READ;
+ vm->mailbox.recv_sender = HF_VM_ID_BASE;
+ vm->mailbox.recv_func = FFA_PARTITION_INFO_GET_32;
+ vm->mailbox.state = MAILBOX_STATE_READ;
/* Return the count of partition information descriptors in w2. */
- ret = (struct ffa_value){.func = FFA_SUCCESS_32, .arg2 = vm_count};
-
-out_unlock:
- vm_unlock(¤t_vm_locked);
-
- return ret;
+ return (struct ffa_value){.func = FFA_SUCCESS_32, .arg2 = vm_count};
}
struct ffa_value api_ffa_partition_info_get(struct vcpu *current,
@@ -441,6 +437,8 @@
FFA_PARTITION_COUNT_FLAG;
bool uuid_is_null = ffa_uuid_is_null(uuid);
struct ffa_partition_info partitions[2 * MAX_VMS];
+ struct vm_locked vm_locked;
+ struct ffa_value ret;
/* Bits 31:1 Must Be Zero */
if ((flags & ~FFA_PARTITION_COUNT_FLAG) != 0) {
@@ -516,8 +514,11 @@
.arg2 = vm_count};
}
- return send_versioned_partition_info_descriptors(current_vm, partitions,
- vm_count);
+ vm_locked = vm_lock(current_vm);
+ ret = send_versioned_partition_info_descriptors(vm_locked, partitions,
+ vm_count);
+ vm_unlock(&vm_locked);
+ return ret;
}
/**