Force manifest booleans to have empty values.

Allowing values such as `<0>` or `"false"` be considered true has the
potential to cause confusion so only accept empty properties as booleans.

Change-Id: I8a9db6a97fc8687ac336138b7b8fc10eee69ae91
diff --git a/inc/hf/manifest.h b/inc/hf/manifest.h
index cfedc61..0e628e5 100644
--- a/inc/hf/manifest.h
+++ b/inc/hf/manifest.h
@@ -66,6 +66,7 @@
 	MANIFEST_ERROR_MALFORMED_INTEGER,
 	MANIFEST_ERROR_INTEGER_OVERFLOW,
 	MANIFEST_ERROR_MALFORMED_INTEGER_LIST,
+	MANIFEST_ERROR_MALFORMED_BOOLEAN,
 };
 
 enum manifest_return_code manifest_init(struct manifest *manifest,
diff --git a/src/manifest.c b/src/manifest.c
index 1933d10..c3b5566 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -55,21 +55,22 @@
 }
 
 /**
- * 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";
+ * Read a boolean property: true if present; false if not. If present, the value
+ * of the property must be empty else it is considered malformed.
  */
-static bool read_bool(const struct fdt_node *node, const char *property)
+static enum manifest_return_code read_bool(const struct fdt_node *node,
+					   const char *property, bool *out)
 {
 	const char *data;
 	uint32_t size;
+	bool present = fdt_read_property(node, property, &data, &size);
 
-	return fdt_read_property(node, property, &data, &size);
+	if (present && size != 0) {
+		return MANIFEST_ERROR_MALFORMED_BOOLEAN;
+	}
+
+	*out = present;
+	return MANIFEST_SUCCESS;
 }
 
 static enum manifest_return_code read_string(const struct fdt_node *node,
@@ -286,8 +287,8 @@
 		dlog("%s SMC whitelist too long.\n", vm->debug_name);
 	}
 
-	vm->smc_whitelist.permissive =
-		read_bool(node, "smc_whitelist_permissive");
+	TRY(read_bool(node, "smc_whitelist_permissive",
+		      &vm->smc_whitelist.permissive));
 
 	if (vm_id == HF_PRIMARY_VM_ID) {
 		TRY(read_optional_string(node, "ramdisk_filename",
@@ -396,6 +397,8 @@
 		return "Integer overflow";
 	case MANIFEST_ERROR_MALFORMED_INTEGER_LIST:
 		return "Malformed integer list property";
+	case MANIFEST_ERROR_MALFORMED_BOOLEAN:
+		return "Malformed boolean property";
 	}
 
 	panic("Unexpected manifest return code.");
diff --git a/src/manifest_test.cc b/src/manifest_test.cc
index 03b6a56..fdfd7f5 100644
--- a/src/manifest_test.cc
+++ b/src/manifest_test.cc
@@ -473,50 +473,47 @@
 	ASSERT_STREQ(string_data(&m.vm[0].primary.ramdisk_filename), "");
 }
 
-TEST(manifest, true_booleans_with_values)
+static std::vector<char> gen_malformed_boolean_dtb(
+	const std::string_view &value)
 {
-	struct manifest m;
-	struct fdt_node fdt_root;
-
 	/* clang-format off */
-	std::vector<char> dtb = ManifestDtBuilder()
+	return  ManifestDtBuilder()
 		.StartChild("hypervisor")
 			.Compatible()
 			.StartChild("vm1")
 				.DebugName("primary_vm")
-				.Property("smc_whitelist_permissive", "\"false\"")
-			.EndChild()
-			.StartChild("vm2")
-				.DebugName("first_secondary_vm")
-				.VcpuCount(42)
-				.MemSize(12345)
-				.Property("smc_whitelist_permissive", "<0>")
-			.EndChild()
-			.StartChild("vm3")
-				.DebugName("second_secondary_vm")
-				.VcpuCount(43)
-				.MemSize(0x12345)
-				.Property("smc_whitelist_permissive", "\"true\"")
-			.EndChild()
-			.StartChild("vm4")
-				.DebugName("tertiary_secondary_vm")
-				.VcpuCount(44)
-				.MemSize(0x55)
-				.Property("smc_whitelist_permissive", "<1>")
+				.Property("smc_whitelist_permissive", value)
 			.EndChild()
 		.EndChild()
 		.Build();
 	/* clang-format on */
+}
 
-	ASSERT_TRUE(get_fdt_root(dtb, &fdt_root));
+TEST(manifest, malformed_booleans)
+{
+	struct manifest m;
+	struct fdt_node fdt_root;
 
-	ASSERT_EQ(manifest_init(&m, &fdt_root), MANIFEST_SUCCESS);
-	ASSERT_EQ(m.vm_count, 4);
+	std::vector<char> dtb_false = gen_malformed_boolean_dtb("\"false\"");
+	std::vector<char> dtb_true = gen_malformed_boolean_dtb("\"true\"");
+	std::vector<char> dtb_0 = gen_malformed_boolean_dtb("\"<0>\"");
+	std::vector<char> dtb_1 = gen_malformed_boolean_dtb("\"<1>\"");
 
-	ASSERT_TRUE(m.vm[0].smc_whitelist.permissive);
-	ASSERT_TRUE(m.vm[1].smc_whitelist.permissive);
-	ASSERT_TRUE(m.vm[2].smc_whitelist.permissive);
-	ASSERT_TRUE(m.vm[3].smc_whitelist.permissive);
+	ASSERT_TRUE(get_fdt_root(dtb_false, &fdt_root));
+	ASSERT_EQ(manifest_init(&m, &fdt_root),
+		  MANIFEST_ERROR_MALFORMED_BOOLEAN);
+
+	ASSERT_TRUE(get_fdt_root(dtb_true, &fdt_root));
+	ASSERT_EQ(manifest_init(&m, &fdt_root),
+		  MANIFEST_ERROR_MALFORMED_BOOLEAN);
+
+	ASSERT_TRUE(get_fdt_root(dtb_0, &fdt_root));
+	ASSERT_EQ(manifest_init(&m, &fdt_root),
+		  MANIFEST_ERROR_MALFORMED_BOOLEAN);
+
+	ASSERT_TRUE(get_fdt_root(dtb_1, &fdt_root));
+	ASSERT_EQ(manifest_init(&m, &fdt_root),
+		  MANIFEST_ERROR_MALFORMED_BOOLEAN);
 }
 
 TEST(manifest, valid)