SPCI: Add a buffer of len PAGE_SIZE to each CPU.
The buffers are used to store a copy of the contents of the Tx buffer
when handling an architected message. This is mostly relevant for
memory sharing.
There exists a single buffer per CPU.
Change-Id: I60c4eab865b01fb73825308439faa72c8af85fb2
diff --git a/inc/hf/cpu.h b/inc/hf/cpu.h
index d44d68e..56f7982 100644
--- a/inc/hf/cpu.h
+++ b/inc/hf/cpu.h
@@ -119,6 +119,8 @@
bool cpu_on(struct cpu *c, ipaddr_t entry, uintreg_t arg);
void cpu_off(struct cpu *c);
struct cpu *cpu_find(cpu_id_t id);
+uint8_t *cpu_get_buffer(cpu_id_t cpu_id);
+uint32_t cpu_get_buffer_size(cpu_id_t cpu_id);
struct vcpu_locked vcpu_lock(struct vcpu *vcpu);
void vcpu_unlock(struct vcpu_locked *locked);
diff --git a/src/api.c b/src/api.c
index 98c0827..1fed670 100644
--- a/src/api.c
+++ b/src/api.c
@@ -936,11 +936,9 @@
* Buffer holding the internal copy of the shared memory
* regions.
*/
- /* TODO: Buffer is temporarily in the stack. */
- uint8_t message_buffer
- [sizeof(struct spci_architected_message_header) +
- sizeof(struct spci_memory_region_constituent) +
- sizeof(struct spci_memory_region)];
+ uint8_t *message_buffer = cpu_get_buffer(current->cpu->id);
+ uint32_t message_buffer_size =
+ cpu_get_buffer_size(current->cpu->id);
struct spci_architected_message_header *architected_header =
spci_get_architected_message_header(from->mailbox.send);
@@ -948,7 +946,7 @@
const struct spci_architected_message_header
*architected_message_replica;
- if (from_msg_replica.length > sizeof(message_buffer)) {
+ if (from_msg_replica.length > message_buffer_size) {
ret = SPCI_INVALID_PARAMETERS;
goto out;
}
@@ -960,7 +958,7 @@
}
/* Copy the architected message into an internal buffer. */
- memcpy_s(message_buffer, sizeof(message_buffer),
+ memcpy_s(message_buffer, message_buffer_size,
architected_header, from_msg_replica.length);
architected_message_replica =
diff --git a/src/cpu.c b/src/cpu.c
index 37de1de..43efa26 100644
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -34,6 +34,31 @@
/* The stack to be used by the CPUs. */
alignas(2 * sizeof(uintreg_t)) static char callstacks[MAX_CPUS][STACK_SIZE];
+/**
+ * Internal buffer used to store SPCI messages from a VM Tx. Its usage prevents
+ * TOCTOU issues while Hafnium performs actions on information that would
+ * otherwise be re-writable by the VM.
+ *
+ * Each buffer is owned by a single cpu. The buffer can only be used for
+ * spci_msg_send. The information stored in the buffer is only valid during the
+ * spci_msg_send request is performed.
+ */
+alignas(PAGE_SIZE) uint8_t cpu_message_buffer[MAX_CPUS][PAGE_SIZE];
+
+uint8_t *cpu_get_buffer(cpu_id_t cpu_id)
+{
+ CHECK(cpu_id < MAX_CPUS);
+
+ return cpu_message_buffer[cpu_id];
+}
+
+uint32_t cpu_get_buffer_size(cpu_id_t cpu_id)
+{
+ CHECK(cpu_id < MAX_CPUS);
+
+ return sizeof(cpu_message_buffer[cpu_id]);
+}
+
/* State of all supported CPUs. The stack of the first one is initialized. */
struct cpu cpus[MAX_CPUS] = {
{