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