Fix panic in vm_find() for reserved IDs
vm_find() is called from VM API and should return NULL if the given ID
does not correspond to a valid VM. This was not the case for ID zero
(reserved for the hypervisor), upon which Hafnium would fail a CHECK
and panic. Fix the issue and add a test case.
Test: hf_vcpu_get_count.reserved_vm_id
Change-Id: I0205e64c5cb5a98cdb24ba2cd75d417845ffaddd
diff --git a/src/vm.c b/src/vm.c
index 08e9531..530ff6b 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -27,15 +27,6 @@
static struct vm vms[MAX_VMS];
static spci_vm_count_t vm_count;
-/**
- * Returns the index of the VM within the VM array.
- */
-static uint16_t vm_get_vm_index(spci_vm_id_t vm_id)
-{
- CHECK(vm_id >= HF_VM_ID_OFFSET);
- return vm_id - HF_VM_ID_OFFSET;
-}
-
bool vm_init(spci_vcpu_count_t vcpu_count, struct mpool *ppool,
struct vm **new_vm)
{
@@ -89,14 +80,21 @@
struct vm *vm_find(spci_vm_id_t id)
{
- uint16_t vm_index = vm_get_vm_index(id);
+ uint16_t index;
- /* Ensure the VM is initialized. */
- if (vm_index >= vm_count) {
+ /* Check that this is not a reserved ID. */
+ if (id < HF_VM_ID_OFFSET) {
return NULL;
}
- return &vms[vm_index];
+ index = id - HF_VM_ID_OFFSET;
+
+ /* Ensure the VM is initialized. */
+ if (index >= vm_count) {
+ return NULL;
+ }
+
+ return &vms[index];
}
/**
diff --git a/test/vmapi/primary_only/primary_only.c b/test/vmapi/primary_only/primary_only.c
index 4bede95..45cbd52 100644
--- a/test/vmapi/primary_only/primary_only.c
+++ b/test/vmapi/primary_only/primary_only.c
@@ -24,6 +24,12 @@
#include "hftest.h"
+/*
+ * TODO: Some of these tests are duplicated between 'primary_only' and
+ * 'primary_with_secondaries'. Move them to a common place consider running
+ * them inside secondary VMs too.
+ */
+
/**
* Confirms the primary VM has the primary ID.
*/
@@ -58,10 +64,22 @@
}
/**
+ * Confirm an error is returned when getting the vcpu count for a reserved ID.
+ */
+TEST(hf_vcpu_get_count, reserved_vm_id)
+{
+ spci_vm_id_t id;
+
+ for (id = 0; id < HF_VM_ID_OFFSET; ++id) {
+ EXPECT_EQ(hf_vcpu_get_count(id), 0);
+ }
+}
+
+/**
* Confirm an error is returned when getting the vcpu count of a VM with an ID
* that is likely to be far outside the resource limit.
*/
-TEST(hf_vcpu_get_count, large_invalid_vm_index)
+TEST(hf_vcpu_get_count, large_invalid_vm_id)
{
EXPECT_EQ(hf_vcpu_get_count(0xffff), 0);
}
diff --git a/test/vmapi/primary_with_secondaries/no_services.c b/test/vmapi/primary_with_secondaries/no_services.c
index 2f2c0b5..edaa90a 100644
--- a/test/vmapi/primary_with_secondaries/no_services.c
+++ b/test/vmapi/primary_with_secondaries/no_services.c
@@ -59,10 +59,22 @@
}
/**
+ * Confirm an error is returned when getting the vcpu count for a reserved ID.
+ */
+TEST(hf_vcpu_get_count, reserved_vm_id)
+{
+ spci_vm_id_t id;
+
+ for (id = 0; id < HF_VM_ID_OFFSET; ++id) {
+ EXPECT_EQ(hf_vcpu_get_count(id), 0);
+ }
+}
+
+/**
* Confirm it is an error to query how many VCPUs are assigned to a nonexistent
* secondary VM.
*/
-TEST(hf_vcpu_get_count, large_invalid_vm_index)
+TEST(hf_vcpu_get_count, large_invalid_vm_id)
{
EXPECT_EQ(hf_vcpu_get_count(0xffff), 0);
}