1 /*
2 * Copyright (c) 2018-2021 Arm Limited
3 * Copyright (c) 2020 Linaro Limited
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include <stddef.h>
19 #include <stdint.h>
20 #include <limits.h>
21 #include <stdbool.h>
22 #include <string.h>
23
24 #include "mcuboot_config/mcuboot_config.h"
25
26 #if defined(MCUBOOT_MEASURED_BOOT) || defined(MCUBOOT_DATA_SHARING)
27 #include "bootutil/boot_record.h"
28 #include "bootutil/boot_status.h"
29 #include "bootutil_priv.h"
30 #include "bootutil/image.h"
31 #include "flash_map_backend/flash_map_backend.h"
32
33 /* Error codes for using the shared memory area. */
34 #define SHARED_MEMORY_OK (0)
35 #define SHARED_MEMORY_OVERFLOW (1)
36 #define SHARED_MEMORY_OVERWRITE (2)
37 #define SHARED_MEMORY_GEN_ERROR (3)
38
39 /**
40 * @var shared_memory_init_done
41 *
42 * @brief Indicates whether shared memory area was already initialized.
43 *
44 */
45 static bool shared_memory_init_done;
46
47 /* See in boot_record.h */
48 int
boot_add_data_to_shared_area(uint8_t major_type,uint16_t minor_type,size_t size,const uint8_t * data)49 boot_add_data_to_shared_area(uint8_t major_type,
50 uint16_t minor_type,
51 size_t size,
52 const uint8_t *data)
53 {
54 struct shared_data_tlv_entry tlv_entry = {0};
55 struct shared_boot_data *boot_data;
56 uint16_t boot_data_size;
57 uintptr_t tlv_end, offset;
58
59 if (data == NULL) {
60 return SHARED_MEMORY_GEN_ERROR;
61 }
62
63 boot_data = (struct shared_boot_data *)MCUBOOT_SHARED_DATA_BASE;
64
65 /* Check whether first time to call this function. If does then initialise
66 * shared data area.
67 */
68 if (!shared_memory_init_done) {
69 memset((void *)MCUBOOT_SHARED_DATA_BASE, 0, MCUBOOT_SHARED_DATA_SIZE);
70 boot_data->header.tlv_magic = SHARED_DATA_TLV_INFO_MAGIC;
71 boot_data->header.tlv_tot_len = SHARED_DATA_HEADER_SIZE;
72 shared_memory_init_done = true;
73 }
74
75 /* Check whether TLV entry is already added.
76 * Get the boundaries of TLV section
77 */
78 tlv_end = MCUBOOT_SHARED_DATA_BASE + boot_data->header.tlv_tot_len;
79 offset = MCUBOOT_SHARED_DATA_BASE + SHARED_DATA_HEADER_SIZE;
80
81 /* Iterates over the TLV section looks for the same entry if found then
82 * returns with error: SHARED_MEMORY_OVERWRITE
83 */
84 while (offset < tlv_end) {
85 /* Create local copy to avoid unaligned access */
86 memcpy(&tlv_entry, (const void *)offset, SHARED_DATA_ENTRY_HEADER_SIZE);
87 if (GET_MAJOR(tlv_entry.tlv_type) == major_type &&
88 GET_MINOR(tlv_entry.tlv_type) == minor_type) {
89 return SHARED_MEMORY_OVERWRITE;
90 }
91
92 offset += SHARED_DATA_ENTRY_SIZE(tlv_entry.tlv_len);
93 }
94
95 /* Add TLV entry */
96 tlv_entry.tlv_type = SET_TLV_TYPE(major_type, minor_type);
97 tlv_entry.tlv_len = size;
98
99 if (!boot_u16_safe_add(&boot_data_size, boot_data->header.tlv_tot_len,
100 SHARED_DATA_ENTRY_SIZE(size))) {
101 return SHARED_MEMORY_GEN_ERROR;
102 }
103
104 /* Verify overflow of shared area */
105 if (boot_data_size > MCUBOOT_SHARED_DATA_SIZE) {
106 return SHARED_MEMORY_OVERFLOW;
107 }
108
109 offset = tlv_end;
110 memcpy((void *)offset, &tlv_entry, SHARED_DATA_ENTRY_HEADER_SIZE);
111
112 offset += SHARED_DATA_ENTRY_HEADER_SIZE;
113 memcpy((void *)offset, data, size);
114
115 boot_data->header.tlv_tot_len += SHARED_DATA_ENTRY_SIZE(size);
116
117 return SHARED_MEMORY_OK;
118 }
119 #endif /* MCUBOOT_MEASURED_BOOT OR MCUBOOT_DATA_SHARING */
120
121 #ifdef MCUBOOT_MEASURED_BOOT
122 /* See in boot_record.h */
123 int
boot_save_boot_status(uint8_t sw_module,const struct image_header * hdr,const struct flash_area * fap)124 boot_save_boot_status(uint8_t sw_module,
125 const struct image_header *hdr,
126 const struct flash_area *fap)
127 {
128
129 struct image_tlv_iter it;
130 uint32_t offset;
131 uint16_t len;
132 uint16_t type;
133 uint16_t ias_minor;
134 size_t record_len = 0;
135 uint8_t image_hash[32]; /* SHA256 - 32 Bytes */
136 uint8_t buf[MAX_BOOT_RECORD_SZ];
137 bool boot_record_found = false;
138 bool hash_found = false;
139 int rc;
140
141 /* Manifest data is concatenated to the end of the image.
142 * It is encoded in TLV format.
143 */
144
145 rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
146 if (rc) {
147 return -1;
148 }
149
150 /* Traverse through the TLV area to find the boot record
151 * and image hash TLVs.
152 */
153 while (true) {
154 rc = bootutil_tlv_iter_next(&it, &offset, &len, &type);
155 if (rc < 0) {
156 return -1;
157 } else if (rc > 0) {
158 break;
159 }
160
161 if (type == IMAGE_TLV_BOOT_RECORD) {
162 if (len > sizeof(buf)) {
163 return -1;
164 }
165 rc = flash_area_read(fap, offset, buf, len);
166 if (rc) {
167 return -1;
168 }
169
170 record_len = len;
171 boot_record_found = true;
172
173 } else if (type == IMAGE_TLV_SHA256) {
174 /* Get the image's hash value from the manifest section. */
175 if (len > sizeof(image_hash)) {
176 return -1;
177 }
178 rc = flash_area_read(fap, offset, image_hash, len);
179 if (rc) {
180 return -1;
181 }
182
183 hash_found = true;
184
185 /* The boot record TLV is part of the protected TLV area which is
186 * located before the other parts of the TLV area (including the
187 * image hash) so at this point it is okay to break the loop
188 * as the boot record TLV should have already been found.
189 */
190 break;
191 }
192 }
193
194
195 if (!boot_record_found || !hash_found) {
196 return -1;
197 }
198
199 /* Ensure that we have enough in the record for the hash. This
200 * prevents an underflow in the calculation below.
201 */
202 if (record_len < sizeof(image_hash)) {
203 return -1;
204 }
205
206 /* Update the measurement value (hash of the image) data item in the
207 * boot record. It is always the last item in the structure to make
208 * it easy to calculate its position.
209 * The image hash is computed over the image header, the image itself and
210 * the protected TLV area (which should already include the image hash as
211 * part of the boot record TLV). For this reason this field has been
212 * filled with zeros during the image signing process.
213 */
214 offset = record_len - sizeof(image_hash);
215 /* The size of 'buf' has already been checked when
216 * the BOOT_RECORD TLV was read, it won't overflow.
217 */
218 memcpy(buf + offset, image_hash, sizeof(image_hash));
219
220 /* Add the CBOR encoded boot record to the shared data area. */
221 ias_minor = SET_IAS_MINOR(sw_module, SW_BOOT_RECORD);
222 rc = boot_add_data_to_shared_area(TLV_MAJOR_IAS,
223 ias_minor,
224 record_len,
225 buf);
226 if (rc != SHARED_MEMORY_OK) {
227 return rc;
228 }
229
230 return 0;
231 }
232 #endif /* MCUBOOT_MEASURED_BOOT */
233