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