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