SMC whitelist from the manifest.
This works for a small number of SMCs. `smc_whitelist` is a list of the
SMCs a VM is allowed to make. `smc_whitelist_permissive` can be set to
allow SMCs through even if they are not whitelisted (for development and
debug).
Bug: 132421503
Change-Id: I64b243d551da35f7625368a72a5a3980d63752f9
diff --git a/src/manifest.c b/src/manifest.c
index 222716f..1933d10 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -18,6 +18,7 @@
#include "hf/addr.h"
#include "hf/check.h"
+#include "hf/dlog.h"
#include "hf/fdt.h"
#include "hf/static_assert.h"
#include "hf/std.h"
@@ -53,6 +54,24 @@
return ptr;
}
+/**
+ * Read a boolean property: true if present; false if not. The value of the
+ * property is ignored.
+ *
+ * This is the convention used by Linux but beware of things like the following
+ * that will actually be considered as `true`.
+ *
+ * true-property0 = <0>;
+ * true-property1 = "false";
+ */
+static bool read_bool(const struct fdt_node *node, const char *property)
+{
+ const char *data;
+ uint32_t size;
+
+ return fdt_read_property(node, property, &data, &size);
+}
+
static enum manifest_return_code read_string(const struct fdt_node *node,
const char *property,
struct string *out)
@@ -121,6 +140,30 @@
return MANIFEST_SUCCESS;
}
+struct uint32list_iter {
+ struct memiter mem_it;
+};
+
+static enum manifest_return_code read_optional_uint32list(
+ const struct fdt_node *node, const char *property,
+ struct uint32list_iter *out)
+{
+ const char *data;
+ uint32_t size;
+
+ if (!fdt_read_property(node, property, &data, &size)) {
+ memiter_init(&out->mem_it, NULL, 0);
+ return MANIFEST_SUCCESS;
+ }
+
+ if ((size % sizeof(uint32_t)) != 0) {
+ return MANIFEST_ERROR_MALFORMED_INTEGER_LIST;
+ }
+
+ memiter_init(&out->mem_it, data, size);
+ return MANIFEST_SUCCESS;
+}
+
/**
* Represents the value of property whose type is a list of strings. These are
* encoded as one contiguous byte buffer with NULL-separated entries.
@@ -152,6 +195,26 @@
return MANIFEST_SUCCESS;
}
+static bool uint32list_has_next(const struct uint32list_iter *list)
+{
+ return memiter_size(&list->mem_it) > 0;
+}
+
+static uint32_t uint32list_get_next(struct uint32list_iter *list)
+{
+ const char *mem_base = memiter_base(&list->mem_it);
+ uint64_t num;
+
+ CHECK(uint32list_has_next(list));
+
+ if (!fdt_parse_number(mem_base, sizeof(uint32_t), &num)) {
+ return MANIFEST_ERROR_MALFORMED_INTEGER;
+ }
+
+ memiter_advance(&list->mem_it, sizeof(uint32_t));
+ return num;
+}
+
static bool stringlist_has_next(const struct stringlist_iter *list)
{
return memiter_size(&list->mem_it) > 0;
@@ -206,9 +269,26 @@
struct manifest_vm *vm,
spci_vm_id_t vm_id)
{
+ struct uint32list_iter smcs;
+
TRY(read_string(node, "debug_name", &vm->debug_name));
TRY(read_optional_string(node, "kernel_filename",
&vm->kernel_filename));
+
+ TRY(read_optional_uint32list(node, "smc_whitelist", &smcs));
+ while (uint32list_has_next(&smcs) &&
+ vm->smc_whitelist.smc_count < MAX_SMCS) {
+ vm->smc_whitelist.smcs[vm->smc_whitelist.smc_count++] =
+ uint32list_get_next(&smcs);
+ }
+
+ if (uint32list_has_next(&smcs)) {
+ dlog("%s SMC whitelist too long.\n", vm->debug_name);
+ }
+
+ vm->smc_whitelist.permissive =
+ read_bool(node, "smc_whitelist_permissive");
+
if (vm_id == HF_PRIMARY_VM_ID) {
TRY(read_optional_string(node, "ramdisk_filename",
&vm->primary.ramdisk_filename));
@@ -314,6 +394,8 @@
return "Malformed integer property";
case MANIFEST_ERROR_INTEGER_OVERFLOW:
return "Integer overflow";
+ case MANIFEST_ERROR_MALFORMED_INTEGER_LIST:
+ return "Malformed integer list property";
}
panic("Unexpected manifest return code.");