1 /*
2  * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 
8 #include <string>
9 #include <cstring>
10 #include <common/uuid/uuid.h>
11 #include <service/block_storage/block_store/device/ram/ram_block_store.h>
12 #include <service/block_storage/config/ref/ref_partition_configurator.h>
13 #include <media/volume/index/volume_index.h>
14 #include <media/volume/block_volume/block_volume.h>
15 #include <media/disk/disk_images/ref_partition.h>
16 #include <media/disk/formatter/disk_formatter.h>
17 #include <media/disk/partition_table.h>
18 #include <CppUTest/TestHarness.h>
19 
TEST_GROUP(PartitionTableTests)20 TEST_GROUP(PartitionTableTests)
21 {
22 	void setup()
23 	{
24 		/* Load reference GPT image into ram block store */
25 		size_t block_size = PLAT_PARTITION_BLOCK_SIZE;
26 		size_t num_blocks = ref_partition_data_length / block_size;
27 
28 		m_block_store = ram_block_store_init(&m_ram_block_store,
29 			NULL,
30 			num_blocks, block_size);
31 
32 		CHECK_TRUE(m_block_store);
33 
34 		memset(m_partition_guid.octets, 0, sizeof(m_partition_guid.octets));
35 
36 		m_volume = NULL;
37 
38 		int result = block_volume_init(&m_block_volume,
39 			m_block_store, &m_partition_guid,
40 			&m_volume);
41 
42 		LONGS_EQUAL(0, result);
43 		CHECK_TRUE(m_volume);
44 
45 		result = disk_formatter_clone(
46 			m_volume->dev_handle, m_volume->io_spec,
47 			ref_partition_data, ref_partition_data_length);
48 
49 		LONGS_EQUAL(0, result);
50 
51 		volume_index_init();
52 		volume_index_add(VOLUME_ID_SECURE_FLASH, m_volume);
53 	}
54 
55 	void teardown()
56 	{
57 		block_volume_deinit(&m_block_volume);
58 		ram_block_store_deinit(&m_ram_block_store);
59 		volume_index_clear();
60 	}
61 
62 	void uuid_from_canonical(uuid_t *uuid, const char *canonical)
63 	{
64 		uuid_parse_to_guid_octets(canonical, (uint8_t*)uuid, sizeof(uuid_t));
65 	}
66 
67 	void corrupt_mbr()
68 	{
69 		/* Scribble over the protective MBR signature */
70 		static const char scribble[] = "scribble";
71 		psa_status_t status = ram_block_store_modify(
72 			&m_ram_block_store, 510,
73 			(const uint8_t*)scribble, sizeof(scribble));
74 		LONGS_EQUAL(PSA_SUCCESS, status);
75 	}
76 
77 	void corrupt_primary_gpt_header()
78 	{
79 		/* Scribble over the primary GPT header in block 1 */
80 		static const char scribble[] = "scribble";
81 		psa_status_t status = ram_block_store_modify(
82 			&m_ram_block_store, PLAT_PARTITION_BLOCK_SIZE * 1,
83 			(const uint8_t*)scribble, sizeof(scribble));
84 		LONGS_EQUAL(PSA_SUCCESS, status);
85 	}
86 
87 	static const uint32_t CLIENT_ID = 0;
88 	static const size_t FIRST_USABLE_LBA = 34;
89 
90 	struct uuid_octets m_partition_guid;
91 	struct block_store *m_block_store;
92 	struct ram_block_store m_ram_block_store;
93 	struct block_volume m_block_volume;
94 	struct volume *m_volume;
95 };
96 
TEST(PartitionTableTests,loadRefPartitionTable)97 TEST(PartitionTableTests, loadRefPartitionTable)
98 {
99 	int result = load_partition_table(VOLUME_ID_SECURE_FLASH);
100 	LONGS_EQUAL(0, result);
101 
102 	/* Check for expected partition entries */
103 	const partition_entry_t *partition_entry = NULL;
104 	uuid_t partition_guid;
105 
106 	uuid_from_canonical(&partition_guid, REF_PARTITION_1_GUID);
107 	partition_entry = get_partition_entry_by_uuid(&partition_guid);
108 	CHECK_TRUE(partition_entry);
109 	UNSIGNED_LONGS_EQUAL(
110 		FIRST_USABLE_LBA + REF_PARTITION_1_STARTING_LBA,
111 		partition_entry->start / PLAT_PARTITION_BLOCK_SIZE);
112 	UNSIGNED_LONGS_EQUAL(
113 		(REF_PARTITION_1_ENDING_LBA - REF_PARTITION_1_STARTING_LBA + 1),
114 		partition_entry->length / PLAT_PARTITION_BLOCK_SIZE);
115 
116 	uuid_from_canonical(&partition_guid, REF_PARTITION_2_GUID);
117 	partition_entry = get_partition_entry_by_uuid(&partition_guid);
118 	CHECK_TRUE(partition_entry);
119 	UNSIGNED_LONGS_EQUAL(
120 		FIRST_USABLE_LBA + REF_PARTITION_2_STARTING_LBA,
121 		partition_entry->start / PLAT_PARTITION_BLOCK_SIZE);
122 	UNSIGNED_LONGS_EQUAL(
123 		(REF_PARTITION_2_ENDING_LBA - REF_PARTITION_2_STARTING_LBA + 1),
124 		partition_entry->length / PLAT_PARTITION_BLOCK_SIZE);
125 
126 	uuid_from_canonical(&partition_guid, REF_PARTITION_3_GUID);
127 	partition_entry = get_partition_entry_by_uuid(&partition_guid);
128 	CHECK_TRUE(partition_entry);
129 	UNSIGNED_LONGS_EQUAL(
130 		FIRST_USABLE_LBA + REF_PARTITION_3_STARTING_LBA,
131 		partition_entry->start / PLAT_PARTITION_BLOCK_SIZE);
132 	UNSIGNED_LONGS_EQUAL(
133 		(REF_PARTITION_3_ENDING_LBA - REF_PARTITION_3_STARTING_LBA + 1),
134 		partition_entry->length / PLAT_PARTITION_BLOCK_SIZE);
135 
136 	uuid_from_canonical(&partition_guid, REF_PARTITION_4_GUID);
137 	partition_entry = get_partition_entry_by_uuid(&partition_guid);
138 	CHECK_TRUE(partition_entry);
139 	UNSIGNED_LONGS_EQUAL(
140 		FIRST_USABLE_LBA + REF_PARTITION_4_STARTING_LBA,
141 		partition_entry->start / PLAT_PARTITION_BLOCK_SIZE);
142 	UNSIGNED_LONGS_EQUAL(
143 		(REF_PARTITION_4_ENDING_LBA - REF_PARTITION_4_STARTING_LBA + 1),
144 		partition_entry->length / PLAT_PARTITION_BLOCK_SIZE);
145 }
146 
TEST(PartitionTableTests,detectCorruptedMbr)147 TEST(PartitionTableTests, detectCorruptedMbr)
148 {
149 	corrupt_mbr();
150 	int result = load_partition_table(VOLUME_ID_SECURE_FLASH);
151 	LONGS_EQUAL(-ENOENT, result);
152 }
153 
154 // Shows up defect in TF-A where failed GPT header CRC results in an assert.
IGNORE_TEST(PartitionTableTests,detectCorruptedGptHeader)155 IGNORE_TEST(PartitionTableTests, detectCorruptedGptHeader)
156 {
157 	/* Load should be successful with a corrupted primary GPT header as
158 	 * backup is still available.
159 	 */
160 	corrupt_primary_gpt_header();
161 	int result = load_partition_table(VOLUME_ID_SECURE_FLASH);
162 	LONGS_EQUAL(0, result);
163 }
164