fix(memory share): checks to allow VM to SP memory share
Fix check made to the memory region structure on memory share operation
to permit calls from the other world.
With the update:
- Hypervisor is allowed to forward the call to the SPMC and sender be a
VM.
- SPMC is allowed to handle call forwarded from the Hypervisor.
- Number of borrowers still limited to one if call to the other
world. This is temporary.
- Lender VM can now specify an FF-A ID belonging to an SP.
Change-Id: I5f740316a8f3d0e2749b8ac68e78c0d482634f8f
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/src/api.c b/src/api.c
index eb09499..705db71 100644
--- a/src/api.c
+++ b/src/api.c
@@ -2851,13 +2851,6 @@
}
memcpy_s(memory_region, MM_PPOOL_ENTRY_SIZE, from_msg, fragment_length);
- /* The sender must match the caller. */
- if (memory_region->sender != from->id) {
- dlog_verbose("Memory region sender doesn't match caller.\n");
- ret = ffa_error(FFA_DENIED);
- goto out;
- }
-
if (!api_memory_region_check_flags(memory_region, share_func)) {
dlog_verbose(
"Memory region reserved arguments must be zero.\n");
@@ -2923,8 +2916,9 @@
/* Allow for one memory region to be shared to the TEE. */
if (targets_other_world) {
- assert(memory_region->receiver_count == 1 &&
- to->id == HF_TEE_VM_ID);
+ assert(memory_region->receiver_count == 1);
+ to = vm_find(HF_OTHER_WORLD_ID);
+
/*
* The 'to' VM lock is only needed in the case that it is the
* TEE VM.
diff --git a/src/ffa_memory.c b/src/ffa_memory.c
index 5826cb2..240b230 100644
--- a/src/ffa_memory.c
+++ b/src/ffa_memory.c
@@ -1393,10 +1393,13 @@
enum ffa_instruction_access instruction_access;
struct ffa_value ret;
- /* The sender must match the message sender. */
- if (memory_region->sender != from_locked.vm->id) {
- dlog_verbose("Invalid sender %d.\n", memory_region->sender);
- return ffa_error(FFA_INVALID_PARAMETERS);
+ /* The sender must match the caller. */
+ if ((!vm_id_is_current_world(from_locked.vm->id) &&
+ vm_id_is_current_world(memory_region->sender)) ||
+ (vm_id_is_current_world(from_locked.vm->id) &&
+ memory_region->sender != from_locked.vm->id)) {
+ dlog_verbose("Invalid memory sender ID.\n");
+ return ffa_error(FFA_DENIED);
}
/*
@@ -1701,6 +1704,22 @@
}
/**
+ * Checks if there is at least one receiver from the other world.
+ */
+static bool memory_region_receivers_from_other_world(
+ struct ffa_memory_region *memory_region)
+{
+ for (uint32_t i = 0; i < memory_region->receiver_count; i++) {
+ ffa_vm_id_t receiver = memory_region->receivers[i]
+ .receiver_permissions.receiver;
+ if (!vm_id_is_current_world(receiver)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
* Validates a call to donate, lend or share memory to a non-TEE VM and then
* updates the stage-2 page tables. Specifically, check if the message length
* and number of memory region constituents match, and if the transition is
@@ -1971,8 +1990,7 @@
}
memory_region = share_state->memory_region;
- if (memory_region->receivers[0].receiver_permissions.receiver ==
- HF_TEE_VM_ID) {
+ if (memory_region_receivers_from_other_world(memory_region)) {
dlog_error(
"Got hypervisor-allocated handle for memory send to "
"TEE. This should never happen, and indicates a bug in "
@@ -2042,8 +2060,7 @@
}
memory_region = share_state->memory_region;
- if (memory_region->receivers[0].receiver_permissions.receiver !=
- HF_TEE_VM_ID) {
+ if (!memory_region_receivers_from_other_world(memory_region)) {
dlog_error(
"Got SPM-allocated handle for memory send to non-TEE "
"VM. This should never happen, and indicates a bug.\n");