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