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