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