1 /*
2  * Copyright (c) 2021, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "uefi_capsule_parser.h"
9 #include "fwu_agent.h"
10 #include <string.h>
11 
12 /*
13 Update Capsule Structure (UEFI spec 2.9 1004)
14     EFI_CAPSULE_HEADER
15     ...
16     ...
17     ...
18     CAPSULE_BODY
19         efi_firmware_management_capsule_header
20         Optional Driver 1 (item_offset[0])
21         Optional Driver 2 (item_offset[1])
22             Payload 1 (item_offset[2])
23                 efi_firmware_management_capsule_iamge_header
24                 Binary Update image (Image_length == update_image_size)
25                 Vendor Code bytes  (Data lenght == update_vendorcode_size)
26             Payload 2 (item_offset[3])
27             ...
28             ...
29             Payload n (item_offset[embedded_driver_count + payload_item_count -1])
30 */
31 
32 typedef struct {
33     struct efi_guid         capsule_guid;
34     uint32_t                header_size;
35     uint32_t                flags;
36     uint32_t                capsule_image_size;
37 } efi_capsule_header_t;
38 
39 typedef struct {
40     uint32_t                version;
41     uint16_t                embedded_driver_count;
42     uint16_t                payload_item_count;
43     uint64_t                item_offset_list[];
44 } efi_firmware_management_capsule_header_t;
45 
46 typedef struct {
47     uint32_t                version;
48     struct efi_guid         update_image_type_id;
49     uint8_t                 update_image_index;
50     uint8_t                 reserved_bytes[3];
51     uint32_t                update_image_size;
52     uint32_t                update_vendorcode_size;
53     uint64_t                update_hardware_instance; //introduced in v2
54     uint64_t                image_capsule_support; //introduced in v3
55 } efi_firmware_management_capsule_image_header_t;
56 
57 typedef struct {
58     uint32_t                signature;
59     uint32_t                header_size;
60     uint32_t                fw_version;
61     uint32_t                lowest_supported_version;
62 } fmp_payload_header_t;
63 
64 #define ANYSIZE_ARRAY 0
65 
66 typedef struct {
67     uint32_t                dwLength;
68     uint16_t                wRevision;
69     uint16_t                wCertificateType;
70     uint8_t                 bCertificate[ANYSIZE_ARRAY];
71 } WIN_CERTIFICATE;
72 
73 typedef struct {
74     WIN_CERTIFICATE         hdr;
75     struct efi_guid         cert_type;
76     uint8_t                 cert_data[ANYSIZE_ARRAY];
77 } win_certificate_uefi_guid_t;
78 
79 typedef struct {
80     uint64_t                    monotonic_count;
81     win_certificate_uefi_guid_t   auth_info;
82 } efi_firmware_image_authentication_t;
83 
84 
uefi_capsule_retrieve_images(void * capsule_ptr,capsule_image_info_t * images_info)85 enum uefi_capsule_error_t uefi_capsule_retrieve_images(void* capsule_ptr,
86         capsule_image_info_t* images_info)
87 {
88     char *ptr = (char*)capsule_ptr;
89     efi_capsule_header_t* capsule_header;
90     efi_firmware_management_capsule_header_t* fmp_capsule_header;
91     efi_firmware_management_capsule_image_header_t* image_header;
92     efi_firmware_image_authentication_t* image_auth;
93     fmp_payload_header_t *fmp_payload_header;
94     uint32_t total_size;
95     uint32_t image_count;
96     uint32_t auth_size;
97 
98     FWU_LOG_MSG("%s: enter, capsule ptr = 0x%p\n\r", __func__, capsule_ptr);
99 
100     if (!capsule_ptr) {
101         return UEFI_CAPSULE_PARSER_ERROR;
102     }
103 
104     capsule_header = (efi_capsule_header_t*)ptr;
105     ptr += sizeof(efi_capsule_header_t);
106     fmp_capsule_header = (efi_firmware_management_capsule_header_t*)ptr;
107 
108     total_size = capsule_header->capsule_image_size;
109     image_count = fmp_capsule_header->payload_item_count;
110     images_info->nr_image = image_count;
111 
112     FWU_LOG_MSG("%s: capsule size = %u, image count = %u\n\r", __func__,
113                         total_size, image_count);
114 
115     if ((image_count == 0) || (image_count > NR_OF_IMAGES_IN_FW_BANK)) {
116         return UEFI_CAPSULE_PARSER_ERROR;
117     }
118 
119     for (int i = 0; i < image_count; i++) {
120         image_header = (efi_firmware_management_capsule_image_header_t*)(ptr +
121                                 fmp_capsule_header->item_offset_list[i]);
122 
123         images_info->size[i] = image_header->update_image_size;
124 
125 #ifdef AUTHENTICATED_CAPSULE
126         image_auth = (efi_firmware_image_authentication_t*)(
127                         (char*)image_header +
128                         sizeof (efi_firmware_management_capsule_image_header_t)
129                      );
130         auth_size = sizeof(uint64_t) /* monotonic_count */  +
131                     image_auth->auth_info.hdr.dwLength/* WIN_CERTIFICATE + cert_data + cert_type */;
132 
133         fmp_payload_header = (fmp_payload_header_t*)((char*)image_auth + auth_size);
134 
135         FWU_LOG_MSG("%s: auth size = %u\n\r", __func__, auth_size);
136 
137         images_info->size[i] -= auth_size;
138 
139         images_info->image[i] = (
140                 (char*)image_header +
141                 sizeof(efi_firmware_management_capsule_image_header_t) +
142                 auth_size +
143                 sizeof(*fmp_payload_header));
144 #else
145         images_info->image[i] = (
146                 (char*)image_header +
147                 sizeof(efi_firmware_management_capsule_image_header_t) +
148                 sizeof(*fmp_payload_header));
149 
150         fmp_payload_header = (fmp_payload_header_t*)((char*)image_header +
151                 sizeof(efi_firmware_management_capsule_image_header_t));
152 
153 #endif
154         memcpy(&images_info->guid[i], &(image_header->update_image_type_id),
155                                                         sizeof(struct efi_guid));
156 
157         images_info->version[i] = fmp_payload_header->fw_version;
158         FWU_LOG_MSG("%s: image %i version = %d\n\r", __func__, i,
159                                 images_info->version[i]);
160 
161         FWU_LOG_MSG("%s: image %d at %p, size=%u\n\r", __func__, i,
162                         images_info->image[i], images_info->size[i]);
163 
164         if ((fmp_capsule_header->item_offset_list[i] +
165              sizeof(efi_firmware_management_capsule_image_header_t) +
166              image_header->update_image_size) > total_size)
167         {
168             return UEFI_CAPSULE_PARSER_ERROR;
169         }
170 
171     }
172 
173     FWU_LOG_MSG("%s: exit\n\r", __func__);
174     return UEFI_CAPSULE_PARSER_SUCCESS;
175 }
176