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