From 186522d2c98a3ca8b5bd73fd3b19f30b4cdac5c4 Mon Sep 17 00:00:00 2001 From: Soren Soe <2106410+stsoe@users.noreply.github.com> Date: Thu, 6 Aug 2026 08:22:08 -0700 Subject: [PATCH 1/7] Fix CWE-125 heap OOB from unterminated fixed-size string fields in section parsers #### Problem solved by the commit Five section parsers passed fixed-size embedded char/uint8_t arrays from wire-format structs directly to boost::format("%s"), which calls strlen internally. If a crafted xclbin fills the last array entry's string field with no null terminator, strlen reads past the end of the heap-allocated section buffer into adjacent memory. Affected fields: - ip_data::m_name (uint8_t[64]) in SectionIPLayout.cxx - clock_freq::m_name (char[128]) in SectionClockFrequencyTopology.cxx - mem_data::m_tag (unsigned char[16]) in SectionMemTopology.cxx - mem_data::m_tag (unsigned char[16]) in SectionGroupTopology.cxx - debug_ip_data::m_name (char[128]) in SectionDebugIPLayout.cxx #### How problem was solved Added XclBinUtilities::bounded_fixed_cstr() template helper that constructs a std::string from a fixed-size array using strnlen to bound the read to N bytes. Applied at all primary put() call sites and TRACE logging sites in all five parsers. #### Risks (if any) associated the changes in the commit Low. For well-formed xclbins the output is identical. For malformed inputs, the string is now truncated at the field boundary rather than reading past the allocation. #### What has been tested and how Built xclbinutil successfully. #### Documentation impact (if any) None Signed-off-by: Soren Soe <2106410+stsoe@users.noreply.github.com> Co-Authored-By: Claude --- .../SectionClockFrequencyTopology.cxx | 4 ++-- .../tools/xclbinutil/SectionDebugIPLayout.cxx | 4 ++-- .../tools/xclbinutil/SectionGroupTopology.cxx | 4 ++-- .../tools/xclbinutil/SectionIPLayout.cxx | 10 +++++----- .../tools/xclbinutil/SectionMemTopology.cxx | 4 ++-- .../tools/xclbinutil/XclBinUtilities.h | 18 ++++++++++++++++++ 6 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/runtime_src/tools/xclbinutil/SectionClockFrequencyTopology.cxx b/src/runtime_src/tools/xclbinutil/SectionClockFrequencyTopology.cxx index 3adac82abc0..24461d9ccea 100644 --- a/src/runtime_src/tools/xclbinutil/SectionClockFrequencyTopology.cxx +++ b/src/runtime_src/tools/xclbinutil/SectionClockFrequencyTopology.cxx @@ -125,14 +125,14 @@ SectionClockFrequencyTopology::marshalToJSON(char* _pDataSection, % index % (unsigned int)pHdr->m_clock_freq[index].m_freq_Mhz % getClockTypeStr((CLOCK_TYPE)pHdr->m_clock_freq[index].m_type) - % pHdr->m_clock_freq[index].m_name); + % XUtil::bounded_fixed_cstr(pHdr->m_clock_freq[index].m_name)); // Write out the entire structure XUtil::TRACE_BUF("clock_freq", reinterpret_cast(&pHdr->m_clock_freq[index]), sizeof(clock_freq)); clock_freq.put("m_freq_Mhz", (boost::format("%d") % (unsigned int)pHdr->m_clock_freq[index].m_freq_Mhz).str()); clock_freq.put("m_type", getClockTypeStr((CLOCK_TYPE)pHdr->m_clock_freq[index].m_type).c_str()); - clock_freq.put("m_name", (boost::format("%s") % pHdr->m_clock_freq[index].m_name).str()); + clock_freq.put("m_name", XUtil::bounded_fixed_cstr(pHdr->m_clock_freq[index].m_name)); m_clock_freq.push_back({ "", clock_freq }); // Used to make an array of objects } diff --git a/src/runtime_src/tools/xclbinutil/SectionDebugIPLayout.cxx b/src/runtime_src/tools/xclbinutil/SectionDebugIPLayout.cxx index b1898e8e536..878bc9c0620 100644 --- a/src/runtime_src/tools/xclbinutil/SectionDebugIPLayout.cxx +++ b/src/runtime_src/tools/xclbinutil/SectionDebugIPLayout.cxx @@ -198,7 +198,7 @@ SectionDebugIPLayout::marshalToJSON(char* _pDataSection, % static_cast(pHdr->m_debug_ip_data[index].m_major) % static_cast(pHdr->m_debug_ip_data[index].m_minor) % pHdr->m_debug_ip_data[index].m_base_address - % pHdr->m_debug_ip_data[index].m_name); + % XUtil::bounded_fixed_cstr(pHdr->m_debug_ip_data[index].m_name)); // Write out the entire structure XUtil::TRACE_BUF("debug_ip_data", reinterpret_cast(&pHdr->m_debug_ip_data[index]), sizeof(debug_ip_data)); @@ -209,7 +209,7 @@ SectionDebugIPLayout::marshalToJSON(char* _pDataSection, debug_ip_data.put("m_major", (boost::format("%d") % static_cast(pHdr->m_debug_ip_data[index].m_major)).str()); debug_ip_data.put("m_minor", (boost::format("%d") % static_cast(pHdr->m_debug_ip_data[index].m_minor)).str()); debug_ip_data.put("m_base_address", (boost::format("0x%lx") % pHdr->m_debug_ip_data[index].m_base_address).str()); - debug_ip_data.put("m_name", (boost::format("%s") % pHdr->m_debug_ip_data[index].m_name).str()); + debug_ip_data.put("m_name", XUtil::bounded_fixed_cstr(pHdr->m_debug_ip_data[index].m_name)); m_debug_ip_data.push_back({ "", debug_ip_data }); // Used to make an array of objects } diff --git a/src/runtime_src/tools/xclbinutil/SectionGroupTopology.cxx b/src/runtime_src/tools/xclbinutil/SectionGroupTopology.cxx index e817b871205..4a6080d719d 100644 --- a/src/runtime_src/tools/xclbinutil/SectionGroupTopology.cxx +++ b/src/runtime_src/tools/xclbinutil/SectionGroupTopology.cxx @@ -160,7 +160,7 @@ SectionGroupTopology::marshalToJSON(char* _pDataSection, % getMemTypeStr((MEM_TYPE)pHdr->m_mem_data[index].m_type) % (unsigned int)pHdr->m_mem_data[index].m_used % pHdr->m_mem_data[index].m_size - % pHdr->m_mem_data[index].m_tag + % XUtil::bounded_fixed_cstr(pHdr->m_mem_data[index].m_tag) % pHdr->m_mem_data[index].m_base_address); // Write out the entire structure @@ -169,7 +169,7 @@ SectionGroupTopology::marshalToJSON(char* _pDataSection, mem_data.put("m_type", getMemTypeStr((MEM_TYPE)pHdr->m_mem_data[index].m_type).c_str()); mem_data.put("m_used", (boost::format("%d") % (unsigned int)pHdr->m_mem_data[index].m_used).str()); mem_data.put("m_sizeKB", (boost::format("0x%lx") % pHdr->m_mem_data[index].m_size).str()); - mem_data.put("m_tag", (boost::format("%s") % pHdr->m_mem_data[index].m_tag).str()); + mem_data.put("m_tag", XUtil::bounded_fixed_cstr(pHdr->m_mem_data[index].m_tag)); mem_data.put("m_base_address", (boost::format("0x%lx") % pHdr->m_mem_data[index].m_base_address).str()); m_mem_data.push_back({ "", mem_data }); // Used to make an array of objects diff --git a/src/runtime_src/tools/xclbinutil/SectionIPLayout.cxx b/src/runtime_src/tools/xclbinutil/SectionIPLayout.cxx index ecd2e51ffef..2570184c9cf 100644 --- a/src/runtime_src/tools/xclbinutil/SectionIPLayout.cxx +++ b/src/runtime_src/tools/xclbinutil/SectionIPLayout.cxx @@ -262,7 +262,7 @@ SectionIPLayout::marshalToJSON(char* _pDataSection, % pHdr->m_ip_data[index].indices.m_index % pHdr->m_ip_data[index].indices.m_pc_index % pHdr->m_ip_data[index].m_base_address - % pHdr->m_ip_data[index].m_name); + % XUtil::bounded_fixed_cstr(pHdr->m_ip_data[index].m_name)); } else if ((IP_TYPE)pHdr->m_ip_data[index].m_type == IP_KERNEL) { std::string sIPControlType = getIPControlTypeStr((IP_CONTROL)((pHdr->m_ip_data[index].properties & ((uint32_t)IP_CONTROL_MASK)) >> IP_CONTROL_SHIFT)); XUtil::TRACE(boost::format("[%d]: m_type: %s, properties: 0x%x {m_ip_control: %s, m_interrupt_id: %d, m_int_enable: %d}, m_base_address: 0x%lx, m_name: '%s'") @@ -273,7 +273,7 @@ SectionIPLayout::marshalToJSON(char* _pDataSection, % ((pHdr->m_ip_data[index].properties & ((uint32_t)IP_INTERRUPT_ID_MASK)) >> IP_INTERRUPT_ID_SHIFT) % (pHdr->m_ip_data[index].properties & ((uint32_t)IP_INT_ENABLE_MASK)) % pHdr->m_ip_data[index].m_base_address - % pHdr->m_ip_data[index].m_name); + % XUtil::bounded_fixed_cstr(pHdr->m_ip_data[index].m_name)); } else { // IP_PS_KERNEL // if m_subtype is ST_DPU (i.e. fixed ps kernel), display "m_subtype", "m_functional" and "m_kernel_id" @@ -286,14 +286,14 @@ SectionIPLayout::marshalToJSON(char* _pDataSection, % getFunctionalStr((PS_FUNCTIONAL)pHdr->m_ip_data[index].ps_kernel.m_functional) % (unsigned int)pHdr->m_ip_data[index].ps_kernel.m_kernel_id % pHdr->m_ip_data[index].m_base_address - % pHdr->m_ip_data[index].m_name); + % XUtil::bounded_fixed_cstr(pHdr->m_ip_data[index].m_name)); } else { XUtil::TRACE(boost::format("[%d]: m_type: %s, properties: 0x%x, m_base_address: 0x%lx, m_name: '%s'") % index % getIPTypeStr((IP_TYPE)pHdr->m_ip_data[index].m_type) % pHdr->m_ip_data[index].properties % pHdr->m_ip_data[index].m_base_address - % pHdr->m_ip_data[index].m_name); + % XUtil::bounded_fixed_cstr(pHdr->m_ip_data[index].m_name)); } } @@ -341,7 +341,7 @@ SectionIPLayout::marshalToJSON(char* _pDataSection, } else { ptIPEntry.put("m_base_address", "not_used"); } - ptIPEntry.put("m_name", (boost::format("%s") % pHdr->m_ip_data[index].m_name).str()); + ptIPEntry.put("m_name", XUtil::bounded_fixed_cstr(pHdr->m_ip_data[index].m_name)); ptIPData.push_back({ "", ptIPEntry }); // Used to make an array of objects } diff --git a/src/runtime_src/tools/xclbinutil/SectionMemTopology.cxx b/src/runtime_src/tools/xclbinutil/SectionMemTopology.cxx index 4d56a221a78..ee0aeb6d98b 100644 --- a/src/runtime_src/tools/xclbinutil/SectionMemTopology.cxx +++ b/src/runtime_src/tools/xclbinutil/SectionMemTopology.cxx @@ -159,7 +159,7 @@ SectionMemTopology::marshalToJSON(char* _pDataSection, % getMemTypeStr((MEM_TYPE)pHdr->m_mem_data[index].m_type) % (unsigned int)pHdr->m_mem_data[index].m_used % pHdr->m_mem_data[index].m_size - % pHdr->m_mem_data[index].m_tag + % XUtil::bounded_fixed_cstr(pHdr->m_mem_data[index].m_tag) % pHdr->m_mem_data[index].m_base_address); // Write out the entire structure @@ -168,7 +168,7 @@ SectionMemTopology::marshalToJSON(char* _pDataSection, mem_data.put("m_type", getMemTypeStr((MEM_TYPE)pHdr->m_mem_data[index].m_type).c_str()); mem_data.put("m_used", (boost::format("%d") % (unsigned int)pHdr->m_mem_data[index].m_used).str()); mem_data.put("m_sizeKB", (boost::format("0x%lx") % pHdr->m_mem_data[index].m_size).str()); - mem_data.put("m_tag", (boost::format("%s") % pHdr->m_mem_data[index].m_tag).str()); + mem_data.put("m_tag", XUtil::bounded_fixed_cstr(pHdr->m_mem_data[index].m_tag)); mem_data.put("m_base_address", (boost::format("0x%lx") % pHdr->m_mem_data[index].m_base_address).str()); m_mem_data.push_back({ "", mem_data }); // Used to make an array of objects diff --git a/src/runtime_src/tools/xclbinutil/XclBinUtilities.h b/src/runtime_src/tools/xclbinutil/XclBinUtilities.h index bdd3312b176..ca4bfcaf797 100644 --- a/src/runtime_src/tools/xclbinutil/XclBinUtilities.h +++ b/src/runtime_src/tools/xclbinutil/XclBinUtilities.h @@ -144,6 +144,24 @@ void safeStringCopy(char* _destBuffer, const std::string& _source, unsigned int // Validates that the offset lies within the buffer and that a null terminator exists // before the buffer end. Throws std::runtime_error on violation (SWSPLAT-30717/CWE-125). const char* bounded_mpo_cstr(const void* pHdr, uint32_t mpo_offset, size_t bufferSize); + +// bounded_fixed_cstr - Safely convert a fixed-size embedded char/uint8_t array (CWE-125). +// Wire-format structs embed fixed-size arrays that may not be null-terminated when an +// attacker controls the xclbin. Returns a std::string of at most N chars, stopping at NUL. +template +std::string +bounded_fixed_cstr(const char (&field)[N]) +{ + return std::string(field, strnlen(field, N)); +} + +template +std::string +bounded_fixed_cstr(const unsigned char (&field)[N]) +{ + return std::string(reinterpret_cast(field), strnlen(reinterpret_cast(field), N)); +} + unsigned int bytesToAlign(uint64_t _offset); unsigned int alignBytes(std::ostream & _buf, unsigned int _byteBoundary); From 4d71932823ae1a2526eeed0d04bb4af7591bc7bc Mon Sep 17 00:00:00 2001 From: Soren Soe <2106410+stsoe@users.noreply.github.com> Date: Thu, 6 Aug 2026 08:26:12 -0700 Subject: [PATCH 2/7] Fix CWE-125 heap OOB from unchecked wire-format array offsets in SectionAIEPartition #### Problem solved by the commit SectionAIEPartition::writeAIEPartitionImage() delegated to helper functions (populate_partition_info, populate_pre_cdo_groups, populate_cdo_groups, populate_PDIs, write_pdi_image) that all used wire-format offset and size fields from the xclbin without any bounds checking against bufferSize. An attacker-controlled xclbin could set any of these fields to cause heap OOB reads: - aie_partition::aie_pdi.offset/size (array of aie_pdi structs) - aie_partition_info::start_columns.offset/size (uint16_t array) - aie_pdi::cdo_groups.offset/size (array of cdo_group structs) - aie_pdi::pdi_image.offset/size (PDI image data, also written to disk) - cdo_group::mpo_name (string offset, missing bounded_mpo_cstr) - cdo_group::dpu_kernel_ids.offset/size (uint64_t array) - cdo_group::pre_cdo_groups.offset/size (uint64_t array) #### How problem was solved Added bufferSize parameter to all helper functions and added overflow-safe bounds checks before forming any pointer from a wire-format offset+count pair: if (count > (bufferSize - offset) / sizeof(T)) throw std::runtime_error(...) Replaced raw pBase+mpo_name with bounded_mpo_cstr() for the CDO group name. pdi_image validated in populate_PDIs before write_pdi_image is called. #### Risks (if any) associated the changes in the commit Low. Rejects malformed xclbins that would previously cause heap OOB reads or write attacker-controlled data to PDI output files. #### What has been tested and how Built xclbinutil successfully. #### Documentation impact (if any) None Signed-off-by: Soren Soe <2106410+stsoe@users.noreply.github.com> Co-Authored-By: Claude --- .../tools/xclbinutil/SectionAIEPartition.cxx | 70 +++++++++++++++---- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/src/runtime_src/tools/xclbinutil/SectionAIEPartition.cxx b/src/runtime_src/tools/xclbinutil/SectionAIEPartition.cxx index defdd165c7c..729d4d63c94 100644 --- a/src/runtime_src/tools/xclbinutil/SectionAIEPartition.cxx +++ b/src/runtime_src/tools/xclbinutil/SectionAIEPartition.cxx @@ -472,6 +472,7 @@ SectionAIEPartition::readSubPayload(const char* pOrigDataSection, static void populate_partition_info(const char* pBase, + size_t bufferSize, const aie_partition_info& aiePartitionInfo, boost::property_tree::ptree& ptAiePartition) { @@ -483,11 +484,19 @@ populate_partition_info(const char* pBase, // Start Columns boost::property_tree::ptree ptStartColumnArray; - const uint16_t* columnArray = reinterpret_cast(pBase + aiePartitionInfo.start_columns.offset); - for (uint32_t index = 0; index < aiePartitionInfo.start_columns.size; index++) { - boost::property_tree::ptree ptElement; - ptElement.put("", (boost::format("%d") % columnArray[index]).str()); - ptStartColumnArray.push_back({ "", ptElement }); + { + const uint64_t offset = aiePartitionInfo.start_columns.offset; + const uint64_t count = aiePartitionInfo.start_columns.size; + if (count > 0) { + if (offset >= bufferSize || count > (bufferSize - offset) / sizeof(uint16_t)) + throw std::runtime_error("aie_partition_info::start_columns offset/size out of bounds"); + const uint16_t* columnArray = reinterpret_cast(pBase + offset); + for (uint32_t index = 0; index < count; index++) { + boost::property_tree::ptree ptElement; + ptElement.put("", (boost::format("%d") % columnArray[index]).str()); + ptStartColumnArray.push_back({ "", ptElement }); + } + } } ptPartitionInfo.add_child("start_columns", ptStartColumnArray); @@ -497,6 +506,7 @@ populate_partition_info(const char* pBase, // ------------------------------------------------------------------------- static void populate_pre_cdo_groups(const char* pBase, + size_t bufferSize, const cdo_group& aieCDOGroup, boost::property_tree::ptree& ptCDOGroup) { @@ -506,6 +516,13 @@ populate_pre_cdo_groups(const char* pBase, if (aieCDOGroup.pre_cdo_groups.size == 0) return; + { + const uint64_t offset = aieCDOGroup.pre_cdo_groups.offset; + const uint64_t count = aieCDOGroup.pre_cdo_groups.size; + if (offset >= bufferSize || count > (bufferSize - offset) / sizeof(uint64_t)) + throw std::runtime_error("cdo_group::pre_cdo_groups offset/size out of bounds"); + } + boost::property_tree::ptree ptPreCDOGroupArray; const uint64_t* aiePreCDOGroupArray = reinterpret_cast(pBase + aieCDOGroup.pre_cdo_groups.offset); @@ -524,19 +541,27 @@ populate_pre_cdo_groups(const char* pBase, // ------------------------------------------------------------------------- static void populate_cdo_groups(const char* pBase, + size_t bufferSize, const aie_pdi& aiePDI, boost::property_tree::ptree& ptAiePDI) { XUtil::TRACE("Populating CDO groups"); boost::property_tree::ptree ptCDOGroupArray; + { + const uint64_t offset = aiePDI.cdo_groups.offset; + const uint64_t count = aiePDI.cdo_groups.size; + if (count > 0 && (offset >= bufferSize || count > (bufferSize - offset) / sizeof(cdo_group))) + throw std::runtime_error("aie_pdi::cdo_groups offset/size out of bounds"); + } + const cdo_group* aieCDOGroupArray = reinterpret_cast(pBase + aiePDI.cdo_groups.offset); for (uint32_t index = 0; index < aiePDI.cdo_groups.size; index++) { const cdo_group& element = aieCDOGroupArray[index]; boost::property_tree::ptree ptElement; // Name - auto sName = reinterpret_cast(pBase + element.mpo_name); + auto sName = XUtil::bounded_mpo_cstr(pBase, element.mpo_name, bufferSize); ptElement.put("name", sName); XUtil::TRACE("Populating CDO group: " + std::string(sName)); @@ -549,9 +574,13 @@ populate_cdo_groups(const char* pBase, // DPU Kernel IDs if (element.dpu_kernel_ids.size) { + const uint64_t kidOffset = element.dpu_kernel_ids.offset; + const uint64_t kidCount = element.dpu_kernel_ids.size; + if (kidOffset >= bufferSize || kidCount > (bufferSize - kidOffset) / sizeof(uint64_t)) + throw std::runtime_error("cdo_group::dpu_kernel_ids offset/size out of bounds"); boost::property_tree::ptree ptDPUKernelIDs; - const uint64_t* kernelIDsArray = reinterpret_cast(pBase + element.dpu_kernel_ids.offset); - for (uint32_t kernelIDindex = 0; kernelIDindex < element.dpu_kernel_ids.size; kernelIDindex++) { + const uint64_t* kernelIDsArray = reinterpret_cast(pBase + kidOffset); + for (uint32_t kernelIDindex = 0; kernelIDindex < kidCount; kernelIDindex++) { boost::property_tree::ptree ptID; ptID.put("", (boost::format("0x%x") % kernelIDsArray[kernelIDindex]).str()); ptDPUKernelIDs.push_back({ "", ptID }); @@ -560,7 +589,7 @@ populate_cdo_groups(const char* pBase, } // Pre cdo groups - populate_pre_cdo_groups(pBase, element, ptElement); + populate_pre_cdo_groups(pBase, bufferSize, element, ptElement); // Add the cdo group element to the array ptCDOGroupArray.push_back({ "", ptElement }); @@ -589,12 +618,14 @@ write_pdi_image(const char* pBase, throw std::runtime_error(errMsg.str()); } + // pdi_image offset/size are validated by the caller before write_pdi_image is invoked. oPDIFile.write(reinterpret_cast(pBase + aiePDI.pdi_image.offset), aiePDI.pdi_image.size); } // ------------------------------------------------------------------------- static void populate_PDIs(const char* pBase, + size_t bufferSize, const fs::path& relativeToDir, const aie_partition& aiePartition, boost::property_tree::ptree& ptAiePartition) @@ -602,6 +633,13 @@ populate_PDIs(const char* pBase, XUtil::TRACE("Populating DPI Array"); boost::property_tree::ptree ptPDIArray; + { + const uint64_t offset = aiePartition.aie_pdi.offset; + const uint64_t count = aiePartition.aie_pdi.size; + if (count > 0 && (offset >= bufferSize || count > (bufferSize - offset) / sizeof(aie_pdi))) + throw std::runtime_error("aie_partition::aie_pdi offset/size out of bounds"); + } + const aie_pdi* aiePdiArray = reinterpret_cast(pBase + aiePartition.aie_pdi.offset); for (uint32_t index = 0; index < aiePartition.aie_pdi.size; index++) { const aie_pdi& element = aiePdiArray[index]; @@ -610,13 +648,21 @@ populate_PDIs(const char* pBase, // UUID ptElement.put("uuid", XUtil::getUUIDAsString(element.uuid)); + // Validate pdi_image before writing + { + const uint64_t imgOffset = element.pdi_image.offset; + const uint64_t imgSize = element.pdi_image.size; + if (imgSize > 0 && (imgOffset >= bufferSize || imgSize > bufferSize - imgOffset)) + throw std::runtime_error("aie_pdi::pdi_image offset/size out of bounds"); + } + // Partition Image std::string fileName = XUtil::getUUIDAsString(element.uuid) + ".pdi"; write_pdi_image(pBase, element, fileName, relativeToDir); ptElement.put("file_name", fileName); // CDO Groups - populate_cdo_groups(pBase, element, ptElement); + populate_cdo_groups(pBase, bufferSize, element, ptElement); // Add the PDI element to the array ptPDIArray.push_back({ "", ptElement }); @@ -664,10 +710,10 @@ writeAIEPartitionImage(const char* pBuffer, ptAiePartition.put("kernel_commit_id", sKernelCommitId); // Partition info - populate_partition_info(pBuffer, pHdr->info, ptAiePartition); + populate_partition_info(pBuffer, bufferSize, pHdr->info, ptAiePartition); // PDIs - populate_PDIs(pBuffer, relativeToDir, *pHdr, ptAiePartition); + populate_PDIs(pBuffer, bufferSize, relativeToDir, *pHdr, ptAiePartition); // Write out the built property tree boost::property_tree::ptree ptRoot; From dd2237b431601148c3faac40b99a57f858f510ef Mon Sep 17 00:00:00 2001 From: Soren Soe <2106410+stsoe@users.noreply.github.com> Date: Thu, 6 Aug 2026 08:29:12 -0700 Subject: [PATCH 3/7] Fix CWE-190/191 integer overflow and underflow in xclbinutil section parsers #### Problem solved by the commit Three integer arithmetic bugs where wire-format-controlled values were used in calculations that could overflow or underflow before a bounds comparison: 1. SectionMCS.cxx: m_chunk::m_offset (uint64_t) was added to a pointer before comparison. Pointer wraparound on x86-64 caused the bounds check to pass for attacker-supplied offsets near UINT64_MAX, enabling heap OOB reads and writes. 2. SectionDNACertificate.cxx: paddingSize was computed as (_sectionSize - signatureSizeBytes) - paddingOffset, which underflows to ~2^64 when paddingOffset > sectionSize - signatureSizeBytes. The guard at line 95 only checked dnaEntriesBitSize/8 <= _sectionSize but did not account for signature overhead, allowing the subsequent binaryBufferToHexString call to read ~2^64 bytes from the heap. 3. XclBinUtilities.cxx: seekg positions were computed as signatureOffset + signature.signedByOffset/signatureOffset using unsigned int arithmetic, which wraps to zero for large values before being widened to std::streamoff. Also added missing gcount() checks. Additionally, the MBG tag compression loop accessed memIndexVector[idx+1] without a bounds guard, causing OOB read on the last element. #### How problem was solved - SectionMCS: check m_offset and m_size directly in offset-space against _sectionSize before forming the pointer. - SectionDNACertificate: tighten the guard to include signatureSizeBytes + sizeof(uint64_t) overhead; add explicit paddingOffset bounds check before subtraction. - XclBinUtilities seekg: cast signatureOffset to uint64_t before adding. - XclBinUtilities MBG loop: add idx+1 < size guard to inner while. #### Risks (if any) associated the changes in the commit Low. All changes tighten input validation; behavior for well-formed inputs is unchanged. #### What has been tested and how Built xclbinutil successfully. #### Documentation impact (if any) None Signed-off-by: Soren Soe <2106410+stsoe@users.noreply.github.com> Co-Authored-By: Claude --- .../tools/xclbinutil/SectionDNACertificate.cxx | 11 ++++++++--- .../tools/xclbinutil/SectionMCS.cxx | 18 +++++++++--------- .../tools/xclbinutil/XclBinUtilities.cxx | 12 ++++++++---- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/runtime_src/tools/xclbinutil/SectionDNACertificate.cxx b/src/runtime_src/tools/xclbinutil/SectionDNACertificate.cxx index c2231429c6c..aba9ee0835b 100644 --- a/src/runtime_src/tools/xclbinutil/SectionDNACertificate.cxx +++ b/src/runtime_src/tools/xclbinutil/SectionDNACertificate.cxx @@ -92,8 +92,8 @@ SectionDNACertificate::marshalToJSON(char* _pDataSection, throw std::runtime_error(errMsg.str()); } - if (((dnaEntriesBitSize / 8) > _sectionSize)) { - auto errMsg = boost::format("ERROR: The message DNA length (0x%x bytes) exceeds the DNA_CERTIFICATE size (0x%x bytes).") % (dnaEntriesBitSize / 8) % _sectionSize; + if (((dnaEntriesBitSize / 8) + signatureSizeBytes + sizeof(uint64_t)) > _sectionSize) { + auto errMsg = boost::format("ERROR: The message DNA length (0x%x bytes) plus overhead exceeds the DNA_CERTIFICATE size (0x%x bytes).") % (dnaEntriesBitSize / 8) % _sectionSize; throw std::runtime_error(errMsg.str()); } @@ -103,7 +103,12 @@ SectionDNACertificate::marshalToJSON(char* _pDataSection, // Get padding string std::string sPadding; uint64_t paddingOffset = dnaEntryCount * dnaEntrySizeBytes; - uint64_t paddingSize = (_sectionSize - signatureSizeBytes) - paddingOffset; + uint64_t usableSize = _sectionSize - signatureSizeBytes; + if (paddingOffset > usableSize) { + auto errMsg = boost::format("ERROR: DNA entries (0x%lx bytes) exceed usable section space (0x%lx bytes).") % paddingOffset % usableSize; + throw std::runtime_error(errMsg.str()); + } + uint64_t paddingSize = usableSize - paddingOffset; XUtil::binaryBufferToHexString((unsigned char*)&_pDataSection[paddingOffset], paddingSize, sPadding); diff --git a/src/runtime_src/tools/xclbinutil/SectionMCS.cxx b/src/runtime_src/tools/xclbinutil/SectionMCS.cxx index b38c50ebcd4..5fb07acfddf 100644 --- a/src/runtime_src/tools/xclbinutil/SectionMCS.cxx +++ b/src/runtime_src/tools/xclbinutil/SectionMCS.cxx @@ -242,21 +242,21 @@ SectionMCS::extractBuffers(const char* _pDataSection, XUtil::TRACE_BUF("m_chunk", reinterpret_cast(&(pHdr->m_chunk[index])), sizeof(mcs_chunk)); - const char* ptrImageBase = _pDataSection + pHdr->m_chunk[index].m_offset; - - // Check to make sure that the MCS image is partially looking good - if ((uint64_t)ptrImageBase > ((uint64_t)_pDataSection) + _sectionSize) { - auto errMsg = boost::format("ERROR: MCS image %d start offset exceeds MCS segment size.") % index; + // Validate offset and size directly in offset-space to avoid pointer wraparound (CWE-190) + const uint64_t chunkOffset = pHdr->m_chunk[index].m_offset; + const uint64_t chunkSize = pHdr->m_chunk[index].m_size; + if (chunkOffset >= _sectionSize) { + auto errMsg = boost::format("ERROR: MCS image %d start offset (0x%lx) exceeds MCS segment size (0x%lx).") % index % chunkOffset % _sectionSize; throw std::runtime_error(errMsg.str()); } - - if (((uint64_t)ptrImageBase) + pHdr->m_chunk[index].m_size > ((uint64_t)_pDataSection) + _sectionSize) { - auto errMsg = boost::format("ERROR: MCS image %d size exceeds the MCS segment size.") % index; + if (chunkSize > _sectionSize - chunkOffset) { + auto errMsg = boost::format("ERROR: MCS image %d size (0x%lx) exceeds the MCS segment size.") % index % chunkSize; throw std::runtime_error(errMsg.str()); } + const char* ptrImageBase = _pDataSection + chunkOffset; std::ostringstream* pBuffer = new std::ostringstream; - pBuffer->write(ptrImageBase, pHdr->m_chunk[index].m_size); + pBuffer->write(ptrImageBase, chunkSize); _mcsBuffers.emplace_back((MCS_TYPE)pHdr->m_chunk[index].m_type, pBuffer); } diff --git a/src/runtime_src/tools/xclbinutil/XclBinUtilities.cxx b/src/runtime_src/tools/xclbinutil/XclBinUtilities.cxx index c90033429a7..03e507224ca 100644 --- a/src/runtime_src/tools/xclbinutil/XclBinUtilities.cxx +++ b/src/runtime_src/tools/xclbinutil/XclBinUtilities.cxx @@ -431,21 +431,25 @@ XclBinUtilities::getSignature(std::fstream& _istream, std::string& _sSignature, _istream.seekg(signatureOffset); _istream.read((char*)&signature, sizeof(XUtil::SignatureHeader)); - // Get signedBy + // Get signedBy — compute seek position as uint64_t to avoid unsigned int overflow (CWE-190) if (signature.signedBySize != 0) { - _istream.seekg(signatureOffset + signature.signedByOffset); + _istream.seekg(static_cast(signatureOffset) + signature.signedByOffset); std::unique_ptr data( new char[ signature.signedBySize ] ); _istream.read( data.get(), signature.signedBySize ); + if (_istream.gcount() != static_cast(signature.signedBySize)) + throw std::runtime_error("ERROR: Short read of signedBy field in signature"); _sSignedBy = std::string(data.get(), signature.signedBySize); } // Get the signature if (signature.signatureSize != 0) { - _istream.seekg(signatureOffset + signature.signatureOffset); + _istream.seekg(static_cast(signatureOffset) + signature.signatureOffset); std::unique_ptr data( new char[ signature.signatureSize ] ); _istream.read( data.get(), signature.signatureSize ); + if (_istream.gcount() != static_cast(signature.signatureSize)) + throw std::runtime_error("ERROR: Short read of signature field"); _sSignature = std::string(data.get(), signature.signatureSize); } @@ -777,7 +781,7 @@ createMemoryBankGroupEntries( std::vector & workingConnection for (unsigned int idx = 0; idx < memIndexVector.size();) { auto s_index = idx; - while ((memIndexVector[idx] + 1) == memIndexVector[idx + 1]) + while ((idx + 1 < memIndexVector.size()) && ((memIndexVector[idx] + 1) == memIndexVector[idx + 1])) idx++; newTag += std::to_string(memIndexVector[s_index]); From 6c99440f10401c0b7386fa7e9b9ca05c916de21a Mon Sep 17 00:00:00 2001 From: Soren Soe <2106410+stsoe@users.noreply.github.com> Date: Thu, 6 Aug 2026 08:31:01 -0700 Subject: [PATCH 4/7] Fix CWE-190 dead guard and silent truncation in Section.cxx readXclBinBinary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### Problem solved by the commit Section.cxx compared m_sectionSize (uint64_t) against UINT64_MAX — a tautologically false check since a uint64_t can never exceed UINT64_MAX. The check was intended to guard the subsequent cast to unsigned int (m_bufferSize), but because it could never fire, any xclbin section with m_sectionSize > UINT32_MAX was silently truncated: the 4-GiB+ value wrapped to a small number, a tiny buffer was allocated, and all downstream consumers used the wrong buffer size without error. The same dead-code pattern appeared in the JSON image path at line ~420. #### How problem was solved Replace `> UINT64_MAX` with `> UINT32_MAX` in both guard locations. This correctly rejects any section whose size exceeds the unsigned int representation used for m_bufferSize. #### Risks (if any) associated the changes in the commit Low. Sections larger than 4 GiB are not valid in practice and would have been silently corrupted before. The new check throws explicitly instead of silently truncating. #### What has been tested and how Built xclbinutil successfully. #### Documentation impact (if any) None Signed-off-by: Soren Soe <2106410+stsoe@users.noreply.github.com> Co-Authored-By: Claude --- src/runtime_src/tools/xclbinutil/Section.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/runtime_src/tools/xclbinutil/Section.cxx b/src/runtime_src/tools/xclbinutil/Section.cxx index 9c58cb3c439..161c57f08d5 100644 --- a/src/runtime_src/tools/xclbinutil/Section.cxx +++ b/src/runtime_src/tools/xclbinutil/Section.cxx @@ -341,8 +341,8 @@ Section::readXclBinBinary(std::istream& _istream, const axlf_section_header& _se m_name = (char*)&_sectionHeader.m_sectionName; - if (_sectionHeader.m_sectionSize > UINT64_MAX) { - std::string errMsg("FATAL ERROR: Section header size exceeds internal representation size."); + if (_sectionHeader.m_sectionSize > UINT32_MAX) { + std::string errMsg("FATAL ERROR: Section header size exceeds maximum supported section size (4 GiB)."); throw std::runtime_error(errMsg); } @@ -417,8 +417,8 @@ Section::readXclBinBinary(std::istream& _istream, XUtil::TRACE(boost::format("Reading in the section '%s' (%d) as a image.") % getSectionKindAsString() % (unsigned int)getSectionKind()); uint64_t imageSize = XUtil::stringToUInt64(_ptSection.get("Size")); - if (imageSize > UINT64_MAX) { - std::string errMsg("FATAL ERROR: Image size exceeds internal representation size."); + if (imageSize > UINT32_MAX) { + std::string errMsg("FATAL ERROR: Image size exceeds maximum supported section size (4 GiB)."); throw std::runtime_error(errMsg); } From 057147924b0d5f546a9df1c7e798dd358a8bf8ea Mon Sep 17 00:00:00 2001 From: Soren Soe <2106410+stsoe@users.noreply.github.com> Date: Thu, 6 Aug 2026 08:32:53 -0700 Subject: [PATCH 5/7] Fix logic bugs: missing empty check on interfaces vector and unchecked stream reads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### Problem solved by the commit Two logic/robustness bugs: 1. XclBinClass.cxx: ptInterfaces[0] was accessed unconditionally after as_vector() without checking whether the vector was empty. A crafted xclbin with partition_metadata that has no "interfaces" entry, or with a non-PR mode xclbin (where the size > 1 check is skipped entirely), caused undefined behavior via std::vector::operator[] on an empty vector — likely a crash. 2. XclBinUtilities.cxx: istream::read() of the SignatureHeader struct had no gcount() check. A truncated file would leave the signature struct zero-initialized; the signedBySize/signatureSize fields would be zero, silently skipping the data reads and masking the corruption. #### How problem was solved 1. Added `if (ptInterfaces.empty()) return;` guard before ptInterfaces[0]. 2. Added gcount() check after the SignatureHeader read, consistent with the existing checks on the signedBy and signature data reads (which were added as part of the Cat 3 fix). #### Risks (if any) associated the changes in the commit Low. The empty-check early return is safe — no interface UUID update occurs for xclbins with no interfaces node, which was already the behavior for well-formed xclbins. The gcount() check rejects truncated signature files that would previously have been silently misprocessed. #### What has been tested and how Built xclbinutil successfully. #### Documentation impact (if any) None Signed-off-by: Soren Soe <2106410+stsoe@users.noreply.github.com> Co-Authored-By: Claude --- src/runtime_src/tools/xclbinutil/XclBinClass.cxx | 3 +++ src/runtime_src/tools/xclbinutil/XclBinUtilities.cxx | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/runtime_src/tools/xclbinutil/XclBinClass.cxx b/src/runtime_src/tools/xclbinutil/XclBinClass.cxx index c4b8e9cb08e..487d08dfd5d 100644 --- a/src/runtime_src/tools/xclbinutil/XclBinClass.cxx +++ b/src/runtime_src/tools/xclbinutil/XclBinClass.cxx @@ -1969,6 +1969,9 @@ XclBin::updateInterfaceuuid() } // Updating axlf header interface_uuid with interface_uuid from partition_metadata + if (ptInterfaces.empty()) + return; + boost::property_tree::ptree ptInterface = ptInterfaces[0]; auto sInterfaceUUID = ptInterface.get("interface_uuid", "00000000-0000-0000-0000-000000000000"); sInterfaceUUID.erase(std::remove(sInterfaceUUID.begin(), sInterfaceUUID.end(), '-'), sInterfaceUUID.end()); // Remove the '-' diff --git a/src/runtime_src/tools/xclbinutil/XclBinUtilities.cxx b/src/runtime_src/tools/xclbinutil/XclBinUtilities.cxx index 03e507224ca..71b38239dcd 100644 --- a/src/runtime_src/tools/xclbinutil/XclBinUtilities.cxx +++ b/src/runtime_src/tools/xclbinutil/XclBinUtilities.cxx @@ -430,6 +430,8 @@ XclBinUtilities::getSignature(std::fstream& _istream, std::string& _sSignature, _istream.seekg(signatureOffset); _istream.read((char*)&signature, sizeof(XUtil::SignatureHeader)); + if (_istream.gcount() != static_cast(sizeof(XUtil::SignatureHeader))) + throw std::runtime_error("ERROR: Short read of signature header"); // Get signedBy — compute seek position as uint64_t to avoid unsigned int overflow (CWE-190) if (signature.signedBySize != 0) From 5b93ef56a13141a87190a6205669b94f384fe951 Mon Sep 17 00:00:00 2001 From: Soren Soe <2106410+stsoe@users.noreply.github.com> Date: Thu, 6 Aug 2026 08:34:59 -0700 Subject: [PATCH 6/7] Fix CWE-78 command injection in legacy popen exec() path in XclBinUtilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### Problem solved by the commit The Boost < 1.64 fallback path in XclBinUtilities::exec() built a shell command line by joining the cmd path and args vector with spaces and passing the result directly to popen(). A user-controlled argument such as an elfLibrary path (--add-pskernel) containing shell metacharacters (e.g. '; rm -rf /') would be executed by the shell. The Boost >= 1.64 path (boost::process::child) passes arguments as a vector, bypassing the shell, so no injection is possible there. #### How problem was solved Added shell_quote() helper that wraps each argument in single quotes and escapes any embedded single quotes as '"'"'. Applied to both the cmd path and every element of args when building the cmdLine string for popen(). This prevents shell interpretation of any characters in user-controlled values regardless of their content. #### Risks (if any) associated the changes in the commit Low. The popen path is only compiled on systems with Boost < 1.64 (pre-2016). The quoting is conservative — paths with spaces or special characters that previously failed will now work correctly. #### What has been tested and how Built xclbinutil successfully. #### Documentation impact (if any) None Signed-off-by: Soren Soe <2106410+stsoe@users.noreply.github.com> Co-Authored-By: Claude --- .../tools/xclbinutil/XclBinUtilities.cxx | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/runtime_src/tools/xclbinutil/XclBinUtilities.cxx b/src/runtime_src/tools/xclbinutil/XclBinUtilities.cxx index 71b38239dcd..1c18f769111 100644 --- a/src/runtime_src/tools/xclbinutil/XclBinUtilities.cxx +++ b/src/runtime_src/tools/xclbinutil/XclBinUtilities.cxx @@ -1249,6 +1249,22 @@ XclBinUtilities::exec(const fs::path &cmd, } #else +// Shell-quote a single argument by wrapping in single quotes and escaping any +// embedded single quotes as '"'"' (end-quote, literal-quote, re-open-quote). +static std::string +shell_quote(const std::string& s) +{ + std::string result = "'"; + for (char c : s) { + if (c == '\'') + result += "'\"'\"'"; + else + result += c; + } + result += "'"; + return result; +} + int XclBinUtilities::exec(const fs::path &cmd, const std::vector &args, @@ -1256,8 +1272,11 @@ XclBinUtilities::exec(const fs::path &cmd, std::ostringstream & os_stdout, std::ostringstream & os_stderr) { - // Build the command line - const std::string cmdLine = cmd.string() + " " + boost::algorithm::join(args, " "); + // Build the command line with each argument individually shell-quoted + // to prevent command injection via user-controlled paths (CWE-78). + std::string cmdLine = shell_quote(cmd.string()); + for (const auto& arg : args) + cmdLine += " " + shell_quote(arg); std::array buffer; std::string result; From 5cb3cc42bfe111e5a9f95df0a2de936b6cd21f3e Mon Sep 17 00:00:00 2001 From: Soren Soe <2106410+stsoe@users.noreply.github.com> Date: Thu, 6 Aug 2026 09:02:05 -0700 Subject: [PATCH 7/7] Review fixes Signed-off-by: Soren Soe <2106410+stsoe@users.noreply.github.com> Co-Authored-By: Claude --- .../tools/xclbinutil/SectionAIEPartition.cxx | 82 +++++++++---------- .../tools/xclbinutil/XclBinUtilities.cxx | 2 + 2 files changed, 39 insertions(+), 45 deletions(-) diff --git a/src/runtime_src/tools/xclbinutil/SectionAIEPartition.cxx b/src/runtime_src/tools/xclbinutil/SectionAIEPartition.cxx index 729d4d63c94..ff2690ffda1 100644 --- a/src/runtime_src/tools/xclbinutil/SectionAIEPartition.cxx +++ b/src/runtime_src/tools/xclbinutil/SectionAIEPartition.cxx @@ -484,18 +484,17 @@ populate_partition_info(const char* pBase, // Start Columns boost::property_tree::ptree ptStartColumnArray; - { - const uint64_t offset = aiePartitionInfo.start_columns.offset; - const uint64_t count = aiePartitionInfo.start_columns.size; - if (count > 0) { - if (offset >= bufferSize || count > (bufferSize - offset) / sizeof(uint16_t)) - throw std::runtime_error("aie_partition_info::start_columns offset/size out of bounds"); - const uint16_t* columnArray = reinterpret_cast(pBase + offset); - for (uint32_t index = 0; index < count; index++) { - boost::property_tree::ptree ptElement; - ptElement.put("", (boost::format("%d") % columnArray[index]).str()); - ptStartColumnArray.push_back({ "", ptElement }); - } + const uint64_t scOffset = aiePartitionInfo.start_columns.offset; + const uint64_t scCount = aiePartitionInfo.start_columns.size; + if (scCount > 0) { + if (scOffset >= bufferSize || scCount > (bufferSize - scOffset) / sizeof(uint16_t)) + throw std::runtime_error("aie_partition_info::start_columns offset/size out of bounds"); + + const uint16_t* columnArray = reinterpret_cast(pBase + scOffset); + for (uint32_t index = 0; index < scCount; index++) { + boost::property_tree::ptree ptElement; + ptElement.put("", (boost::format("%d") % columnArray[index]).str()); + ptStartColumnArray.push_back({ "", ptElement }); } } ptPartitionInfo.add_child("start_columns", ptStartColumnArray); @@ -516,17 +515,15 @@ populate_pre_cdo_groups(const char* pBase, if (aieCDOGroup.pre_cdo_groups.size == 0) return; - { - const uint64_t offset = aieCDOGroup.pre_cdo_groups.offset; - const uint64_t count = aieCDOGroup.pre_cdo_groups.size; - if (offset >= bufferSize || count > (bufferSize - offset) / sizeof(uint64_t)) - throw std::runtime_error("cdo_group::pre_cdo_groups offset/size out of bounds"); - } + const uint64_t offset = aieCDOGroup.pre_cdo_groups.offset; + const uint64_t count = aieCDOGroup.pre_cdo_groups.size; + if (offset >= bufferSize || count > (bufferSize - offset) / sizeof(uint64_t)) + throw std::runtime_error("cdo_group::pre_cdo_groups offset/size out of bounds"); boost::property_tree::ptree ptPreCDOGroupArray; - const uint64_t* aiePreCDOGroupArray = reinterpret_cast(pBase + aieCDOGroup.pre_cdo_groups.offset); - for (uint32_t index = 0; index < aieCDOGroup.pre_cdo_groups.size; index++) { + const uint64_t* aiePreCDOGroupArray = reinterpret_cast(pBase + offset); + for (uint32_t index = 0; index < count; index++) { const uint64_t& element = aiePreCDOGroupArray[index]; boost::property_tree::ptree ptElement; @@ -548,15 +545,13 @@ populate_cdo_groups(const char* pBase, XUtil::TRACE("Populating CDO groups"); boost::property_tree::ptree ptCDOGroupArray; - { - const uint64_t offset = aiePDI.cdo_groups.offset; - const uint64_t count = aiePDI.cdo_groups.size; - if (count > 0 && (offset >= bufferSize || count > (bufferSize - offset) / sizeof(cdo_group))) - throw std::runtime_error("aie_pdi::cdo_groups offset/size out of bounds"); - } + const uint64_t cdoOffset = aiePDI.cdo_groups.offset; + const uint64_t cdoCount = aiePDI.cdo_groups.size; + if (cdoCount > 0 && (cdoOffset >= bufferSize || cdoCount > (bufferSize - cdoOffset) / sizeof(cdo_group))) + throw std::runtime_error("aie_pdi::cdo_groups offset/size out of bounds"); - const cdo_group* aieCDOGroupArray = reinterpret_cast(pBase + aiePDI.cdo_groups.offset); - for (uint32_t index = 0; index < aiePDI.cdo_groups.size; index++) { + const cdo_group* aieCDOGroupArray = reinterpret_cast(pBase + cdoOffset); + for (uint32_t index = 0; index < cdoCount; index++) { const cdo_group& element = aieCDOGroupArray[index]; boost::property_tree::ptree ptElement; @@ -573,11 +568,12 @@ populate_cdo_groups(const char* pBase, ptElement.put("pdi_id", (boost::format("0x%x") % element.pdi_id).str()); // DPU Kernel IDs - if (element.dpu_kernel_ids.size) { - const uint64_t kidOffset = element.dpu_kernel_ids.offset; - const uint64_t kidCount = element.dpu_kernel_ids.size; + const uint64_t kidOffset = element.dpu_kernel_ids.offset; + const uint64_t kidCount = element.dpu_kernel_ids.size; + if (kidCount > 0) { if (kidOffset >= bufferSize || kidCount > (bufferSize - kidOffset) / sizeof(uint64_t)) throw std::runtime_error("cdo_group::dpu_kernel_ids offset/size out of bounds"); + boost::property_tree::ptree ptDPUKernelIDs; const uint64_t* kernelIDsArray = reinterpret_cast(pBase + kidOffset); for (uint32_t kernelIDindex = 0; kernelIDindex < kidCount; kernelIDindex++) { @@ -633,15 +629,13 @@ populate_PDIs(const char* pBase, XUtil::TRACE("Populating DPI Array"); boost::property_tree::ptree ptPDIArray; - { - const uint64_t offset = aiePartition.aie_pdi.offset; - const uint64_t count = aiePartition.aie_pdi.size; - if (count > 0 && (offset >= bufferSize || count > (bufferSize - offset) / sizeof(aie_pdi))) - throw std::runtime_error("aie_partition::aie_pdi offset/size out of bounds"); - } + const uint64_t pdiOffset = aiePartition.aie_pdi.offset; + const uint64_t pdiCount = aiePartition.aie_pdi.size; + if (pdiCount > 0 && (pdiOffset >= bufferSize || pdiCount > (bufferSize - pdiOffset) / sizeof(aie_pdi))) + throw std::runtime_error("aie_partition::aie_pdi offset/size out of bounds"); - const aie_pdi* aiePdiArray = reinterpret_cast(pBase + aiePartition.aie_pdi.offset); - for (uint32_t index = 0; index < aiePartition.aie_pdi.size; index++) { + const aie_pdi* aiePdiArray = reinterpret_cast(pBase + pdiOffset); + for (uint32_t index = 0; index < pdiCount; index++) { const aie_pdi& element = aiePdiArray[index]; boost::property_tree::ptree ptElement; @@ -649,12 +643,10 @@ populate_PDIs(const char* pBase, ptElement.put("uuid", XUtil::getUUIDAsString(element.uuid)); // Validate pdi_image before writing - { - const uint64_t imgOffset = element.pdi_image.offset; - const uint64_t imgSize = element.pdi_image.size; - if (imgSize > 0 && (imgOffset >= bufferSize || imgSize > bufferSize - imgOffset)) - throw std::runtime_error("aie_pdi::pdi_image offset/size out of bounds"); - } + const uint64_t imgOffset = element.pdi_image.offset; + const uint64_t imgSize = element.pdi_image.size; + if (imgSize > 0 && (imgOffset >= bufferSize || imgSize > bufferSize - imgOffset)) + throw std::runtime_error("aie_pdi::pdi_image offset/size out of bounds"); // Partition Image std::string fileName = XUtil::getUUIDAsString(element.uuid) + ".pdi"; diff --git a/src/runtime_src/tools/xclbinutil/XclBinUtilities.cxx b/src/runtime_src/tools/xclbinutil/XclBinUtilities.cxx index 1c18f769111..4cc6b08d393 100644 --- a/src/runtime_src/tools/xclbinutil/XclBinUtilities.cxx +++ b/src/runtime_src/tools/xclbinutil/XclBinUtilities.cxx @@ -441,6 +441,7 @@ XclBinUtilities::getSignature(std::fstream& _istream, std::string& _sSignature, _istream.read( data.get(), signature.signedBySize ); if (_istream.gcount() != static_cast(signature.signedBySize)) throw std::runtime_error("ERROR: Short read of signedBy field in signature"); + _sSignedBy = std::string(data.get(), signature.signedBySize); } @@ -452,6 +453,7 @@ XclBinUtilities::getSignature(std::fstream& _istream, std::string& _sSignature, _istream.read( data.get(), signature.signatureSize ); if (_istream.gcount() != static_cast(signature.signatureSize)) throw std::runtime_error("ERROR: Short read of signature field"); + _sSignature = std::string(data.get(), signature.signatureSize); }