xref: /openbmc/pldm/fw-update/package_parser.cpp (revision 4d99c311)
1 #include "package_parser.hpp"
2 
3 #include "common/utils.hpp"
4 
5 #include <libpldm/firmware_update.h>
6 #include <libpldm/utils.h>
7 
8 #include <phosphor-logging/lg2.hpp>
9 #include <xyz/openbmc_project/Common/error.hpp>
10 
11 #include <memory>
12 
13 PHOSPHOR_LOG2_USING;
14 
15 namespace pldm
16 {
17 
18 namespace fw_update
19 {
20 
21 using InternalFailure =
22     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
23 
24 size_t PackageParser::parseFDIdentificationArea(
25     DeviceIDRecordCount deviceIdRecCount, const std::vector<uint8_t>& pkgHdr,
26     size_t offset)
27 {
28     size_t pkgHdrRemainingSize = pkgHdr.size() - offset;
29 
30     while (deviceIdRecCount-- && (pkgHdrRemainingSize > 0))
31     {
32         pldm_firmware_device_id_record deviceIdRecHeader{};
33         variable_field applicableComponents{};
34         variable_field compImageSetVersionStr{};
35         variable_field recordDescriptors{};
36         variable_field fwDevicePkgData{};
37 
38         auto rc = decode_firmware_device_id_record(
39             pkgHdr.data() + offset, pkgHdrRemainingSize,
40             componentBitmapBitLength, &deviceIdRecHeader, &applicableComponents,
41             &compImageSetVersionStr, &recordDescriptors, &fwDevicePkgData);
42         if (rc)
43         {
44             error("Decoding firmware device ID record failed, RC={RC}", "RC",
45                   rc);
46             throw InternalFailure();
47         }
48 
49         Descriptors descriptors{};
50         while (deviceIdRecHeader.descriptor_count-- &&
51                (recordDescriptors.length > 0))
52         {
53             uint16_t descriptorType = 0;
54             variable_field descriptorData{};
55 
56             rc = decode_descriptor_type_length_value(
57                 recordDescriptors.ptr, recordDescriptors.length,
58                 &descriptorType, &descriptorData);
59             if (rc)
60             {
61                 error(
62                     "Decoding descriptor type, length and value failed, RC={RC}",
63                     "RC", rc);
64                 throw InternalFailure();
65             }
66 
67             if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
68             {
69                 descriptors.emplace(
70                     descriptorType,
71                     DescriptorData{descriptorData.ptr,
72                                    descriptorData.ptr + descriptorData.length});
73             }
74             else
75             {
76                 uint8_t descTitleStrType = 0;
77                 variable_field descTitleStr{};
78                 variable_field vendorDefinedDescData{};
79 
80                 rc = decode_vendor_defined_descriptor_value(
81                     descriptorData.ptr, descriptorData.length,
82                     &descTitleStrType, &descTitleStr, &vendorDefinedDescData);
83                 if (rc)
84                 {
85                     error(
86                         "Decoding Vendor-defined descriptor value failed, RC={RC}",
87                         "RC", rc);
88                     throw InternalFailure();
89                 }
90 
91                 descriptors.emplace(
92                     descriptorType,
93                     std::make_tuple(utils::toString(descTitleStr),
94                                     VendorDefinedDescriptorData{
95                                         vendorDefinedDescData.ptr,
96                                         vendorDefinedDescData.ptr +
97                                             vendorDefinedDescData.length}));
98             }
99 
100             auto nextDescriptorOffset =
101                 sizeof(pldm_descriptor_tlv().descriptor_type) +
102                 sizeof(pldm_descriptor_tlv().descriptor_length) +
103                 descriptorData.length;
104             recordDescriptors.ptr += nextDescriptorOffset;
105             recordDescriptors.length -= nextDescriptorOffset;
106         }
107 
108         DeviceUpdateOptionFlags deviceUpdateOptionFlags =
109             deviceIdRecHeader.device_update_option_flags.value;
110 
111         ApplicableComponents componentsList;
112 
113         for (size_t varBitfieldIdx = 0;
114              varBitfieldIdx < applicableComponents.length; varBitfieldIdx++)
115         {
116             std::bitset<8> entry{*(applicableComponents.ptr + varBitfieldIdx)};
117             for (size_t idx = 0; idx < entry.size(); idx++)
118             {
119                 if (entry[idx])
120                 {
121                     componentsList.emplace_back(
122                         idx + (varBitfieldIdx * entry.size()));
123                 }
124             }
125         }
126 
127         fwDeviceIDRecords.emplace_back(std::make_tuple(
128             deviceUpdateOptionFlags, componentsList,
129             utils::toString(compImageSetVersionStr), std::move(descriptors),
130             FirmwareDevicePackageData{fwDevicePkgData.ptr,
131                                       fwDevicePkgData.ptr +
132                                           fwDevicePkgData.length}));
133         offset += deviceIdRecHeader.record_length;
134         pkgHdrRemainingSize -= deviceIdRecHeader.record_length;
135     }
136 
137     return offset;
138 }
139 
140 size_t PackageParser::parseCompImageInfoArea(ComponentImageCount compImageCount,
141                                              const std::vector<uint8_t>& pkgHdr,
142                                              size_t offset)
143 {
144     size_t pkgHdrRemainingSize = pkgHdr.size() - offset;
145 
146     while (compImageCount-- && (pkgHdrRemainingSize > 0))
147     {
148         pldm_component_image_information compImageInfo{};
149         variable_field compVersion{};
150 
151         auto rc = decode_pldm_comp_image_info(pkgHdr.data() + offset,
152                                               pkgHdrRemainingSize,
153                                               &compImageInfo, &compVersion);
154         if (rc)
155         {
156             error("Decoding component image information failed, RC={RC}", "RC",
157                   rc);
158             throw InternalFailure();
159         }
160 
161         CompClassification compClassification =
162             compImageInfo.comp_classification;
163         CompIdentifier compIdentifier = compImageInfo.comp_identifier;
164         CompComparisonStamp compComparisonTime =
165             compImageInfo.comp_comparison_stamp;
166         CompOptions compOptions = compImageInfo.comp_options.value;
167         ReqCompActivationMethod reqCompActivationMethod =
168             compImageInfo.requested_comp_activation_method.value;
169         CompLocationOffset compLocationOffset =
170             compImageInfo.comp_location_offset;
171         CompSize compSize = compImageInfo.comp_size;
172 
173         componentImageInfos.emplace_back(std::make_tuple(
174             compClassification, compIdentifier, compComparisonTime, compOptions,
175             reqCompActivationMethod, compLocationOffset, compSize,
176             utils::toString(compVersion)));
177         offset += sizeof(pldm_component_image_information) +
178                   compImageInfo.comp_version_string_length;
179         pkgHdrRemainingSize -= sizeof(pldm_component_image_information) +
180                                compImageInfo.comp_version_string_length;
181     }
182 
183     return offset;
184 }
185 
186 void PackageParser::validatePkgTotalSize(uintmax_t pkgSize)
187 {
188     uintmax_t calcPkgSize = pkgHeaderSize;
189     for (const auto& componentImageInfo : componentImageInfos)
190     {
191         CompLocationOffset compLocOffset = std::get<static_cast<size_t>(
192             ComponentImageInfoPos::CompLocationOffsetPos)>(componentImageInfo);
193         CompSize compSize =
194             std::get<static_cast<size_t>(ComponentImageInfoPos::CompSizePos)>(
195                 componentImageInfo);
196 
197         if (compLocOffset != calcPkgSize)
198         {
199             auto cmpVersion = std::get<static_cast<size_t>(
200                 ComponentImageInfoPos::CompVersionPos)>(componentImageInfo);
201             error(
202                 "Validating the component location offset failed, COMP_VERSION={COMP_VERS}",
203                 "COMP_VERS", cmpVersion);
204             throw InternalFailure();
205         }
206 
207         calcPkgSize += compSize;
208     }
209 
210     if (calcPkgSize != pkgSize)
211     {
212         error(
213             "Package size does not match calculated package size, PKG_SIZE={PKG_SIZE}, CALC_PKG_SIZE={CAL_PKG_SIZE}",
214             "PKG_SIZE", pkgSize, "CAL_PKG_SIZE", calcPkgSize);
215         throw InternalFailure();
216     }
217 }
218 
219 void PackageParserV1::parse(const std::vector<uint8_t>& pkgHdr,
220                             uintmax_t pkgSize)
221 {
222     if (pkgHeaderSize != pkgHdr.size())
223     {
224         error("Package header size is invalid, PKG_HDR_SIZE={PKG_HDR_SIZE}",
225               "PKG_HDR_SIZE", pkgHeaderSize);
226         throw InternalFailure();
227     }
228 
229     size_t offset = sizeof(pldm_package_header_information) + pkgVersion.size();
230     if (offset + sizeof(DeviceIDRecordCount) >= pkgHeaderSize)
231     {
232         error("Parsing package header failed, PKG_HDR_SIZE={PKG_HDR_SIZE}",
233               "PKG_HDR_SIZE", pkgHeaderSize);
234         throw InternalFailure();
235     }
236 
237     auto deviceIdRecCount = static_cast<DeviceIDRecordCount>(pkgHdr[offset]);
238     offset += sizeof(DeviceIDRecordCount);
239 
240     offset = parseFDIdentificationArea(deviceIdRecCount, pkgHdr, offset);
241     if (deviceIdRecCount != fwDeviceIDRecords.size())
242     {
243         error(
244             "DeviceIDRecordCount entries not found, DEVICE_ID_REC_COUNT={DREC_CNT}",
245             "DREC_CNT", deviceIdRecCount);
246         throw InternalFailure();
247     }
248     if (offset + sizeof(ComponentImageCount) >= pkgHeaderSize)
249     {
250         error("Parsing package header failed, PKG_HDR_SIZE={PKG_HDR_SIZE}",
251               "PKG_HDR_SIZE", pkgHeaderSize);
252         throw InternalFailure();
253     }
254 
255     auto compImageCount = static_cast<ComponentImageCount>(
256         le16toh(pkgHdr[offset] | (pkgHdr[offset + 1] << 8)));
257     offset += sizeof(ComponentImageCount);
258 
259     offset = parseCompImageInfoArea(compImageCount, pkgHdr, offset);
260     if (compImageCount != componentImageInfos.size())
261     {
262         error(
263             "ComponentImageCount entries not found, COMP_IMAGE_COUNT={COMP_IMG_CNT}",
264             "COMP_IMG_CNT", compImageCount);
265         throw InternalFailure();
266     }
267 
268     if (offset + sizeof(PackageHeaderChecksum) != pkgHeaderSize)
269     {
270         error("Parsing package header failed, PKG_HDR_SIZE={PKG_HDR_SIZE}",
271               "PKG_HDR_SIZE", pkgHeaderSize);
272         throw InternalFailure();
273     }
274 
275     auto calcChecksum = crc32(pkgHdr.data(), offset);
276     auto checksum = static_cast<PackageHeaderChecksum>(
277         le32toh(pkgHdr[offset] | (pkgHdr[offset + 1] << 8) |
278                 (pkgHdr[offset + 2] << 16) | (pkgHdr[offset + 3] << 24)));
279     if (calcChecksum != checksum)
280     {
281         error(
282             "Parsing package header failed, CALC_CHECKSUM={CHK_SUM}, PKG_HDR_CHECKSUM={PKG_HDR_CHK_SUM}",
283             "CHK_SUM", calcChecksum, "PKG_HDR_CHK_SUM", checksum);
284         throw InternalFailure();
285     }
286 
287     validatePkgTotalSize(pkgSize);
288 }
289 
290 std::unique_ptr<PackageParser> parsePkgHeader(std::vector<uint8_t>& pkgData)
291 {
292     constexpr std::array<uint8_t, PLDM_FWUP_UUID_LENGTH> hdrIdentifierv1{
293         0xF0, 0x18, 0x87, 0x8C, 0xCB, 0x7D, 0x49, 0x43,
294         0x98, 0x00, 0xA0, 0x2F, 0x05, 0x9A, 0xCA, 0x02};
295     constexpr uint8_t pkgHdrVersion1 = 0x01;
296 
297     pldm_package_header_information pkgHeader{};
298     variable_field pkgVersion{};
299     auto rc = decode_pldm_package_header_info(pkgData.data(), pkgData.size(),
300                                               &pkgHeader, &pkgVersion);
301     if (rc)
302     {
303         error("Decoding PLDM package header information failed, RC={RC}", "RC",
304               rc);
305         return nullptr;
306     }
307 
308     if (std::equal(pkgHeader.uuid, pkgHeader.uuid + PLDM_FWUP_UUID_LENGTH,
309                    hdrIdentifierv1.begin(), hdrIdentifierv1.end()) &&
310         (pkgHeader.package_header_format_version == pkgHdrVersion1))
311     {
312         PackageHeaderSize pkgHdrSize = pkgHeader.package_header_size;
313         ComponentBitmapBitLength componentBitmapBitLength =
314             pkgHeader.component_bitmap_bit_length;
315         return std::make_unique<PackageParserV1>(
316             pkgHdrSize, utils::toString(pkgVersion), componentBitmapBitLength);
317     }
318 
319     return nullptr;
320 }
321 
322 } // namespace fw_update
323 
324 } // namespace pldm
325