1From 5fd2662e1f20b5c645ff0755e84424bae303fa45 Mon Sep 17 00:00:00 2001
2From: Bence Balogh <bence.balogh@arm.com>
3Date: Mon, 9 Sep 2024 09:42:58 +0200
4Subject: [PATCH] Platform: CS1000: Validate both metadata replicas
5
6According to the [1] both metadata replica integrity should be checked
7during the update agent initialization, and if one of the replica is
8corrupted then it should be fixed by copying the other replica.
9
10This commit:
11- Adds the integrity check and correction to the
12  corstone1000_fwu_host_ack() function. This function is called when
13  the Host core has booted.
14- Updates the metadata_read() function so both replica can be read.
15- Adds metadata_write_replica() function to write metadata replicas
16  separately.
17
18[1] https://developer.arm.com/documentation/den0118/a/?lang=en
19
20Signed-off-by: Bence Balogh <bence.balogh@arm.com>
21Upstream-Status: Pending [Not submitted to upstream yet]
22---
23 .../corstone1000/fw_update_agent/fwu_agent.c  | 167 ++++++++++++------
24 .../corstone1000/fw_update_agent/fwu_agent.h  |   7 +
25 2 files changed, 119 insertions(+), 55 deletions(-)
26
27diff --git a/platform/ext/target/arm/corstone1000/fw_update_agent/fwu_agent.c b/platform/ext/target/arm/corstone1000/fw_update_agent/fwu_agent.c
28index 92b918c67..aad6208e0 100644
29--- a/platform/ext/target/arm/corstone1000/fw_update_agent/fwu_agent.c
30+++ b/platform/ext/target/arm/corstone1000/fw_update_agent/fwu_agent.c
31@@ -395,20 +395,33 @@ static enum fwu_agent_error_t metadata_read_without_validation(struct fwu_metada
32 #endif
33
34 #ifdef BL1_BUILD
35-static enum fwu_agent_error_t metadata_read(struct fwu_metadata *p_metadata)
36+static enum fwu_agent_error_t metadata_read(struct fwu_metadata *p_metadata, uint8_t replica_num)
37 {
38     int ret;
39+    uint32_t replica_offset = 0;
40
41-    FWU_LOG_MSG("%s: enter: flash addr = %u, size = %d\n\r", __func__,
42-                  FWU_METADATA_REPLICA_1_OFFSET, sizeof(struct fwu_metadata));
43+    FWU_LOG_MSG("%s: enter\n\r", __func__);
44
45     if (!p_metadata) {
46         return FWU_AGENT_ERROR;
47     }
48
49-    ret = FWU_METADATA_FLASH_DEV.ReadData(FWU_METADATA_REPLICA_1_OFFSET,
50-                                p_metadata, sizeof(struct fwu_metadata));
51-    if (ret < 0 || ret != sizeof(struct fwu_metadata)) {
52+    if (replica_num == 1) {
53+        replica_offset = FWU_METADATA_REPLICA_1_OFFSET;
54+    } else if (replica_num == 2) {
55+        replica_offset = FWU_METADATA_REPLICA_2_OFFSET;
56+    } else {
57+        FWU_LOG_MSG("%s: replica_num must be 1 or 2\n\r", __func__);
58+        return FWU_AGENT_ERROR;
59+    }
60+
61+    FWU_LOG_MSG("%s: flash addr = %u, size = %d\n\r", __func__,
62+                  replica_offset, sizeof(*p_metadata));
63+
64+
65+    ret = FWU_METADATA_FLASH_DEV.ReadData(replica_offset,
66+                                p_metadata, sizeof(*p_metadata));
67+    if (ret < 0 || ret != sizeof(*p_metadata)) {
68         return FWU_AGENT_ERROR;
69     }
70
71@@ -422,17 +435,27 @@ static enum fwu_agent_error_t metadata_read(struct fwu_metadata *p_metadata)
72     return FWU_AGENT_SUCCESS;
73 }
74 #else
75-static enum fwu_agent_error_t metadata_read(struct fwu_metadata *p_metadata)
76+static enum fwu_agent_error_t metadata_read(struct fwu_metadata *p_metadata, uint8_t replica_num)
77 {
78     uuid_t metadata_uuid = FWU_METADATA_TYPE_UUID;
79     partition_entry_t *part;
80     int ret;
81
82+    FWU_LOG_MSG("%s: enter\n\r", __func__);
83+
84     if (!p_metadata) {
85         return FWU_AGENT_ERROR;
86     }
87
88-    part = get_partition_entry_by_type(&metadata_uuid);
89+    if (replica_num == 1) {
90+        part = get_partition_entry_by_type(&metadata_uuid);
91+    } else if (replica_num == 2) {
92+        part = get_partition_replica_by_type(&metadata_uuid);
93+    } else {
94+        FWU_LOG_MSG("%s: replica_num must be 1 or 2\n\r", __func__);
95+        return FWU_AGENT_ERROR;
96+    }
97+
98     if (!part) {
99         FWU_LOG_MSG("%s: FWU metadata partition not found\n\r", __func__);
100         return FWU_AGENT_ERROR;
101@@ -461,39 +484,38 @@ static enum fwu_agent_error_t metadata_read(struct fwu_metadata *p_metadata)
102
103 #ifdef BL1_BUILD
104 static enum fwu_agent_error_t metadata_write(
105-                        struct fwu_metadata *p_metadata)
106+                        struct fwu_metadata *p_metadata, uint8_t replica_num)
107 {
108     int ret;
109+    uint32_t replica_offset = 0;
110
111-    FWU_LOG_MSG("%s: enter: flash addr = %u, size = %d\n\r", __func__,
112-                  FWU_METADATA_REPLICA_1_OFFSET, sizeof(struct fwu_metadata));
113+    FWU_LOG_MSG("%s: enter\n\r", __func__);
114
115     if (!p_metadata) {
116         return FWU_AGENT_ERROR;
117     }
118
119-    ret = FWU_METADATA_FLASH_DEV.EraseSector(FWU_METADATA_REPLICA_1_OFFSET);
120-    if (ret != ARM_DRIVER_OK) {
121-        return FWU_AGENT_ERROR;
122-    }
123-
124-    ret = FWU_METADATA_FLASH_DEV.ProgramData(FWU_METADATA_REPLICA_1_OFFSET,
125-                                p_metadata, sizeof(struct fwu_metadata));
126-    if (ret < 0 || ret != sizeof(struct fwu_metadata)) {
127+    if (replica_num == 1) {
128+        replica_offset = FWU_METADATA_REPLICA_1_OFFSET;
129+    } else if (replica_num == 2) {
130+        replica_offset = FWU_METADATA_REPLICA_2_OFFSET;
131+    } else {
132+        FWU_LOG_MSG("%s: replica_num must be 1 or 2\n\r", __func__);
133         return FWU_AGENT_ERROR;
134     }
135
136     FWU_LOG_MSG("%s: enter: flash addr = %u, size = %d\n\r", __func__,
137-                  FWU_METADATA_REPLICA_2_OFFSET, sizeof(struct fwu_metadata));
138+                  replica_offset, sizeof(*p_metadata));
139
140-    ret = FWU_METADATA_FLASH_DEV.EraseSector(FWU_METADATA_REPLICA_2_OFFSET);
141+
142+    ret = FWU_METADATA_FLASH_DEV.EraseSector(replica_offset);
143     if (ret != ARM_DRIVER_OK) {
144         return FWU_AGENT_ERROR;
145     }
146
147-    ret = FWU_METADATA_FLASH_DEV.ProgramData(FWU_METADATA_REPLICA_2_OFFSET,
148-                                p_metadata, sizeof(struct fwu_metadata));
149-    if (ret < 0 || ret != sizeof(struct fwu_metadata)) {
150+    ret = FWU_METADATA_FLASH_DEV.ProgramData(replica_offset,
151+                                p_metadata, sizeof(*p_metadata));
152+    if (ret < 0 || ret != sizeof(*p_metadata)) {
153         return FWU_AGENT_ERROR;
154     }
155
156@@ -503,7 +525,7 @@ static enum fwu_agent_error_t metadata_write(
157 }
158 #else
159 static enum fwu_agent_error_t metadata_write(
160-                        struct fwu_metadata *p_metadata)
161+                        struct fwu_metadata *p_metadata, uint8_t replica_num)
162 {
163     uuid_t metadata_uuid = FWU_METADATA_TYPE_UUID;
164     partition_entry_t *part;
165@@ -513,7 +535,15 @@ static enum fwu_agent_error_t metadata_write(
166         return FWU_AGENT_ERROR;
167     }
168
169-    part = get_partition_entry_by_type(&metadata_uuid);
170+    if (replica_num == 1) {
171+        part = get_partition_entry_by_type(&metadata_uuid);
172+    } else if (replica_num == 2) {
173+        part = get_partition_replica_by_type(&metadata_uuid);
174+    } else {
175+        FWU_LOG_MSG("%s: replica_num must be 1 or 2\n\r", __func__);
176+        return FWU_AGENT_ERROR;
177+    }
178+
179     if (!part) {
180         FWU_LOG_MSG("%s: FWU metadata partition not found\n\r", __func__);
181         return FWU_AGENT_ERROR;
182@@ -533,32 +563,51 @@ static enum fwu_agent_error_t metadata_write(
183         return FWU_AGENT_ERROR;
184     }
185
186-    part = get_partition_replica_by_type(&metadata_uuid);
187-    if (!part) {
188-        FWU_LOG_MSG("%s: FWU metadata replica partition not found\n\r", __func__);
189-        return FWU_AGENT_ERROR;
190-    }
191+    FWU_LOG_MSG("%s: success: active = %u, previous = %d\n\r", __func__,
192+                  p_metadata->active_index, p_metadata->previous_active_index);
193+    return FWU_AGENT_SUCCESS;
194+}
195+#endif
196
197-    FWU_LOG_MSG("%s: enter: flash addr = %u, size = %d\n\r", __func__,
198-                  part->start, sizeof(struct fwu_metadata));
199+static enum fwu_agent_error_t metadata_write_both_replica(
200+                        struct fwu_metadata *p_metadata)
201+{
202+    enum fwu_agent_error_t ret = FWU_AGENT_ERROR;
203
204-    ret = FWU_METADATA_FLASH_DEV.EraseSector(part->start);
205-    if (ret != ARM_DRIVER_OK) {
206-        return FWU_AGENT_ERROR;
207+    ret = metadata_write(&_metadata, 1);
208+    if (ret) {
209+        return ret;
210     }
211
212-    ret = FWU_METADATA_FLASH_DEV.ProgramData(part->start,
213-                                p_metadata, sizeof(struct fwu_metadata));
214-    if (ret < 0 || ret != sizeof(struct fwu_metadata)) {
215-        return FWU_AGENT_ERROR;
216+    ret = metadata_write(&_metadata, 2);
217+    if (ret) {
218+        return ret;
219     }
220
221-    FWU_LOG_MSG("%s: success: active = %u, previous = %d\n\r", __func__,
222-                  p_metadata->active_index, p_metadata->previous_active_index);
223     return FWU_AGENT_SUCCESS;
224 }
225-#endif
226
227+enum fwu_agent_error_t fwu_metadata_check_and_correct_integrity(void)
228+{
229+    enum fwu_agent_error_t ret_replica_1 = FWU_AGENT_ERROR;
230+    enum fwu_agent_error_t ret_replica_2 = FWU_AGENT_ERROR;
231+
232+    /* Check integrity of both metadata replica */
233+    ret_replica_1 = metadata_read(&_metadata, 1);
234+    ret_replica_2 = metadata_read(&_metadata, 2);
235+
236+    if (ret_replica_1 != FWU_AGENT_SUCCESS && ret_replica_2 != FWU_AGENT_SUCCESS) {
237+        return FWU_AGENT_ERROR;
238+    } else if (ret_replica_1 == FWU_AGENT_SUCCESS && ret_replica_2 != FWU_AGENT_SUCCESS) {
239+        metadata_read(&_metadata, 1);
240+        metadata_write(&_metadata, 2);
241+    } else if (ret_replica_1 != FWU_AGENT_SUCCESS && ret_replica_2 == FWU_AGENT_SUCCESS) {
242+        metadata_read(&_metadata, 2);
243+        metadata_write(&_metadata, 1);
244+    }
245+
246+    return FWU_AGENT_SUCCESS;
247+}
248
249 enum fwu_agent_error_t fwu_metadata_init(void)
250 {
251@@ -617,8 +666,8 @@ enum fwu_agent_error_t fwu_metadata_provision(void)
252      * had a firmware data?. If yes, then don't initialize
253      * metadata
254      */
255-    metadata_read(&_metadata);
256-    if(_metadata.active_index < 2 || _metadata.previous_active_index <2){
257+    metadata_read(&_metadata, 1);
258+    if(_metadata.active_index < 2 || _metadata.previous_active_index < 2){
259     	if(_metadata.active_index ^ _metadata.previous_active_index)
260     		return FWU_AGENT_SUCCESS;
261     }
262@@ -652,13 +701,13 @@ enum fwu_agent_error_t fwu_metadata_provision(void)
263     _metadata.crc_32 = crc32((uint8_t *)&_metadata.version,
264                              sizeof(struct fwu_metadata) - sizeof(uint32_t));
265
266-    ret = metadata_write(&_metadata);
267+    ret = metadata_write_both_replica(&_metadata);
268     if (ret) {
269         return ret;
270     }
271
272-    memset(&_metadata, 0, sizeof(struct fwu_metadata));
273-    ret = metadata_read(&_metadata);
274+    memset(&_metadata, 0, sizeof(_metadata));
275+    ret = metadata_read(&_metadata, 1);
276     if (ret) {
277         return ret;
278     }
279@@ -825,7 +874,7 @@ static enum fwu_agent_error_t flash_full_capsule(
280     metadata->crc_32 = crc32((uint8_t *)&metadata->version,
281                               sizeof(struct fwu_metadata) - sizeof(uint32_t));
282
283-    ret = metadata_write(metadata);
284+    ret = metadata_write_both_replica(metadata);
285     if (ret) {
286         return ret;
287     }
288@@ -852,7 +901,7 @@ enum fwu_agent_error_t corstone1000_fwu_flash_image(void)
289
290     Select_Write_Mode_For_Shared_Flash();
291
292-    if (metadata_read(&_metadata)) {
293+    if (metadata_read(&_metadata, 1)) {
294         ret =  FWU_AGENT_ERROR;
295         goto out;
296     }
297@@ -938,7 +987,7 @@ static enum fwu_agent_error_t accept_full_capsule(
298     metadata->crc_32 = crc32((uint8_t *)&metadata->version,
299                               sizeof(struct fwu_metadata) - sizeof(uint32_t));
300
301-    ret = metadata_write(metadata);
302+    ret = metadata_write_both_replica(metadata);
303     if (ret) {
304         return ret;
305     }
306@@ -1034,7 +1083,7 @@ static enum fwu_agent_error_t fwu_select_previous(
307     metadata->crc_32 = crc32((uint8_t *)&metadata->version,
308                               sizeof(struct fwu_metadata) - sizeof(uint32_t));
309
310-    ret = metadata_write(metadata);
311+    ret = metadata_write_both_replica(metadata);
312     if (ret) {
313         return ret;
314     }
315@@ -1064,7 +1113,7 @@ void bl1_get_active_bl2_image(uint32_t *offset)
316         FWU_ASSERT(0);
317     }
318
319-    if (metadata_read(&_metadata)) {
320+    if (metadata_read(&_metadata, 1)) {
321         FWU_ASSERT(0);
322     }
323
324@@ -1203,9 +1252,17 @@ enum fwu_agent_error_t corstone1000_fwu_host_ack(void)
325         return FWU_AGENT_ERROR;
326     }
327
328+    /* This cannot be added to the fwu_metadata_init() because that function is
329+     * called before the logging is enabled by TF-M. */
330+    ret = fwu_metadata_check_and_correct_integrity();
331+    if (ret = FWU_AGENT_SUCCESS) {
332+        FWU_LOG_MSG("fwu_metadata_check_and_correct_integrity failed\r\n");
333+        return ret;
334+    }
335+
336     Select_Write_Mode_For_Shared_Flash();
337
338-    if (metadata_read(&_metadata)) {
339+    if (metadata_read(&_metadata, 1)) {
340         ret = FWU_AGENT_ERROR;
341         goto out;
342     }
343@@ -1315,7 +1372,7 @@ void host_acknowledgement_timer_to_reset(void)
344         FWU_ASSERT(0);
345     }
346
347-    if (metadata_read(&_metadata)) {
348+    if (metadata_read(&_metadata, 1)) {
349         FWU_ASSERT(0);
350     }
351
352diff --git a/platform/ext/target/arm/corstone1000/fw_update_agent/fwu_agent.h b/platform/ext/target/arm/corstone1000/fw_update_agent/fwu_agent.h
353index 701f20558..78e104277 100644
354--- a/platform/ext/target/arm/corstone1000/fw_update_agent/fwu_agent.h
355+++ b/platform/ext/target/arm/corstone1000/fw_update_agent/fwu_agent.h
356@@ -70,4 +70,11 @@ enum fwu_nv_counter_index_t {
357 enum fwu_agent_error_t fwu_stage_nv_counter(enum fwu_nv_counter_index_t index,
358         uint32_t img_security_cnt);
359
360+/*
361+ * Check if both metadata replica is valid by calculating and comparing crc32.
362+ * If one of the replica is corrupted then update it with the valid replica.
363+ * If both of the replicas are corrupted then the correction is not possible.
364+ */
365+enum fwu_agent_error_t fwu_metadata_check_and_correct_integrity(void);
366+
367 #endif /* FWU_AGENT_H */
368--
3692.25.1
370
371