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