Coverage Report

Created: 2026-07-16 06:33

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