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 it is, then check
66 * whether the shared data area needs to be initialised.
67 */
68 if (!shared_memory_init_done) {
69 if ((boot_data->header.tlv_magic != SHARED_DATA_TLV_INFO_MAGIC) ||
70 (boot_data->header.tlv_tot_len > MCUBOOT_SHARED_DATA_SIZE)) {
71 memset((void *)MCUBOOT_SHARED_DATA_BASE, 0,
72 MCUBOOT_SHARED_DATA_SIZE);
73 boot_data->header.tlv_magic = SHARED_DATA_TLV_INFO_MAGIC;
74 boot_data->header.tlv_tot_len = SHARED_DATA_HEADER_SIZE;
75 }
76
77 shared_memory_init_done = true;
78 }
79
80 /* Check whether TLV entry is already added.
81 * Get the boundaries of TLV section
82 */
83 tlv_end = MCUBOOT_SHARED_DATA_BASE + boot_data->header.tlv_tot_len;
84 offset = MCUBOOT_SHARED_DATA_BASE + SHARED_DATA_HEADER_SIZE;
85
86 /* Iterates over the TLV section looks for the same entry if found then
87 * returns with error: SHARED_MEMORY_OVERWRITE
88 */
89 while (offset < tlv_end) {
90 /* Create local copy to avoid unaligned access */
91 memcpy(&tlv_entry, (const void *)offset, SHARED_DATA_ENTRY_HEADER_SIZE);
92 if (GET_MAJOR(tlv_entry.tlv_type) == major_type &&
93 GET_MINOR(tlv_entry.tlv_type) == minor_type) {
94 return SHARED_MEMORY_OVERWRITE;
95 }
96
97 offset += SHARED_DATA_ENTRY_SIZE(tlv_entry.tlv_len);
98 }
99
100 /* Add TLV entry */
101 tlv_entry.tlv_type = SET_TLV_TYPE(major_type, minor_type);
102 tlv_entry.tlv_len = size;
103
104 if (!boot_u16_safe_add(&boot_data_size, boot_data->header.tlv_tot_len,
105 SHARED_DATA_ENTRY_SIZE(size))) {
106 return SHARED_MEMORY_GEN_ERROR;
107 }
108
109 /* Verify overflow of shared area */
110 if (boot_data_size > MCUBOOT_SHARED_DATA_SIZE) {
111 return SHARED_MEMORY_OVERFLOW;
112 }
113
114 offset = tlv_end;
115 memcpy((void *)offset, &tlv_entry, SHARED_DATA_ENTRY_HEADER_SIZE);
116
117 offset += SHARED_DATA_ENTRY_HEADER_SIZE;
118 memcpy((void *)offset, data, size);
119
120 boot_data->header.tlv_tot_len += SHARED_DATA_ENTRY_SIZE(size);
121
122 return SHARED_MEMORY_OK;
123 }
124 #endif /* MCUBOOT_MEASURED_BOOT OR MCUBOOT_DATA_SHARING */
125
126 #ifdef MCUBOOT_MEASURED_BOOT
127 /* See in boot_record.h */
128 int
boot_save_boot_status(uint8_t sw_module,const struct image_header * hdr,const struct flash_area * fap)129 boot_save_boot_status(uint8_t sw_module,
130 const struct image_header *hdr,
131 const struct flash_area *fap)
132 {
133
134 struct image_tlv_iter it;
135 uint32_t offset;
136 uint16_t len;
137 uint16_t type;
138 uint16_t ias_minor;
139 size_t record_len = 0;
140 uint8_t image_hash[32]; /* SHA256 - 32 Bytes */
141 uint8_t buf[MAX_BOOT_RECORD_SZ];
142 bool boot_record_found = false;
143 bool hash_found = false;
144 int rc;
145
146 /* Manifest data is concatenated to the end of the image.
147 * It is encoded in TLV format.
148 */
149
150 rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
151 if (rc) {
152 return -1;
153 }
154
155 /* Traverse through the TLV area to find the boot record
156 * and image hash TLVs.
157 */
158 while (true) {
159 rc = bootutil_tlv_iter_next(&it, &offset, &len, &type);
160 if (rc < 0) {
161 return -1;
162 } else if (rc > 0) {
163 break;
164 }
165
166 if (type == IMAGE_TLV_BOOT_RECORD) {
167 if (len > sizeof(buf)) {
168 return -1;
169 }
170 rc = flash_area_read(fap, offset, buf, len);
171 if (rc) {
172 return -1;
173 }
174
175 record_len = len;
176 boot_record_found = true;
177
178 } else if (type == IMAGE_TLV_SHA256) {
179 /* Get the image's hash value from the manifest section. */
180 if (len > sizeof(image_hash)) {
181 return -1;
182 }
183 rc = flash_area_read(fap, offset, image_hash, len);
184 if (rc) {
185 return -1;
186 }
187
188 hash_found = true;
189
190 /* The boot record TLV is part of the protected TLV area which is
191 * located before the other parts of the TLV area (including the
192 * image hash) so at this point it is okay to break the loop
193 * as the boot record TLV should have already been found.
194 */
195 break;
196 }
197 }
198
199
200 if (!boot_record_found || !hash_found) {
201 return -1;
202 }
203
204 /* Update the measurement value (hash of the image) data item in the
205 * boot record. It is always the last item in the structure to make
206 * it easy to calculate its position.
207 * The image hash is computed over the image header, the image itself and
208 * the protected TLV area (which should already include the image hash as
209 * part of the boot record TLV). For this reason this field has been
210 * filled with zeros during the image signing process.
211 */
212 offset = record_len - sizeof(image_hash);
213 /* The size of 'buf' has already been checked when
214 * the BOOT_RECORD TLV was read, it won't overflow.
215 */
216 memcpy(buf + offset, image_hash, sizeof(image_hash));
217
218 /* Add the CBOR encoded boot record to the shared data area. */
219 ias_minor = SET_IAS_MINOR(sw_module, SW_BOOT_RECORD);
220 rc = boot_add_data_to_shared_area(TLV_MAJOR_IAS,
221 ias_minor,
222 record_len,
223 buf);
224 if (rc != SHARED_MEMORY_OK) {
225 return rc;
226 }
227
228 return 0;
229 }
230 #endif /* MCUBOOT_MEASURED_BOOT */
231