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( 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 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 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 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 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