-
Notifications
You must be signed in to change notification settings - Fork 535
Adding OOB checks in the xclbin_parser #9589
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,4 +1,5 @@ | ||||||||||||||||||||||||||||||||||||||||
| /* | ||||||||||||||||||||||||||||||||||||||||
| * Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved. | ||||||||||||||||||||||||||||||||||||||||
| * Copyright (C) 2019-2022 Xilinx, Inc | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * Licensed under the Apache License, Version 2.0 (the "License"). You may | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -835,13 +836,28 @@ get_softkernels(const axlf* top) | |||||||||||||||||||||||||||||||||||||||
| pSection != nullptr; | ||||||||||||||||||||||||||||||||||||||||
| pSection = ::xclbin::get_axlf_section_next(top, pSection, SOFT_KERNEL)) { | ||||||||||||||||||||||||||||||||||||||||
| auto begin = reinterpret_cast<const char*>(top) + pSection->m_sectionOffset; | ||||||||||||||||||||||||||||||||||||||||
| auto section_size = pSection->m_sectionSize; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if (section_size < sizeof(soft_kernel)) | ||||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| auto soft = reinterpret_cast<const soft_kernel*>(begin); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if (soft->mpo_symbol_name >= section_size || | ||||||||||||||||||||||||||||||||||||||||
| soft->mpo_name >= section_size || | ||||||||||||||||||||||||||||||||||||||||
| soft->mpo_version >= section_size || | ||||||||||||||||||||||||||||||||||||||||
| soft->m_image_offset >= section_size || | ||||||||||||||||||||||||||||||||||||||||
| (soft->m_image_offset + soft->m_image_size) > section_size) | ||||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| softkernel_object sko; | ||||||||||||||||||||||||||||||||||||||||
| sko.ninst = soft->m_num_instances; | ||||||||||||||||||||||||||||||||||||||||
| sko.symbol_name = std::string(begin + soft->mpo_symbol_name); | ||||||||||||||||||||||||||||||||||||||||
| sko.mpo_name = std::string(begin + soft->mpo_name); | ||||||||||||||||||||||||||||||||||||||||
| sko.mpo_version = std::string(begin + soft->mpo_version); | ||||||||||||||||||||||||||||||||||||||||
| sko.symbol_name = std::string(begin + soft->mpo_symbol_name, | ||||||||||||||||||||||||||||||||||||||||
| strnlen(begin + soft->mpo_symbol_name, section_size - soft->mpo_symbol_name)); | ||||||||||||||||||||||||||||||||||||||||
| sko.mpo_name = std::string(begin + soft->mpo_name, | ||||||||||||||||||||||||||||||||||||||||
| strnlen(begin + soft->mpo_name, section_size - soft->mpo_name)); | ||||||||||||||||||||||||||||||||||||||||
| sko.mpo_version = std::string(begin + soft->mpo_version, | ||||||||||||||||||||||||||||||||||||||||
| strnlen(begin + soft->mpo_version, section_size - soft->mpo_version)); | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+855
to
+860
|
||||||||||||||||||||||||||||||||||||||||
| sko.size = soft->m_image_size; | ||||||||||||||||||||||||||||||||||||||||
| sko.sk_buf = const_cast<char*>(begin + soft->m_image_offset); // NOLINT | ||||||||||||||||||||||||||||||||||||||||
| sks.emplace_back(std::move(sko)); | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -858,29 +874,77 @@ get_aie_partition(const axlf* top) | |||||||||||||||||||||||||||||||||||||||
| return {}; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| auto topbase = reinterpret_cast<const char*>(top) + pSection->m_sectionOffset; | ||||||||||||||||||||||||||||||||||||||||
| auto section_size = pSection->m_sectionSize; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if (section_size < sizeof(aie_partition)) | ||||||||||||||||||||||||||||||||||||||||
| return {}; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| auto aiep = reinterpret_cast<const aie_partition*>(topbase); | ||||||||||||||||||||||||||||||||||||||||
| auto scp = reinterpret_cast<const uint16_t*>(topbase + aiep->info.start_columns.offset); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| aie_partition_obj obj{aiep->info.column_width, {scp, scp + aiep->info.start_columns.size}, topbase + aiep->mpo_name, aiep->operations_per_cycle}; | ||||||||||||||||||||||||||||||||||||||||
| if (aiep->mpo_name >= section_size) | ||||||||||||||||||||||||||||||||||||||||
| return {}; | ||||||||||||||||||||||||||||||||||||||||
| if (aiep->info.start_columns.offset >= section_size) | ||||||||||||||||||||||||||||||||||||||||
| return {}; | ||||||||||||||||||||||||||||||||||||||||
| size_t start_cols_bytes = static_cast<size_t>(aiep->info.start_columns.size) * sizeof(uint16_t); | ||||||||||||||||||||||||||||||||||||||||
| if (start_cols_bytes > section_size || | ||||||||||||||||||||||||||||||||||||||||
| aiep->info.start_columns.offset > section_size - start_cols_bytes) | ||||||||||||||||||||||||||||||||||||||||
| return {}; | ||||||||||||||||||||||||||||||||||||||||
| if (aiep->aie_pdi.offset >= section_size) | ||||||||||||||||||||||||||||||||||||||||
| return {}; | ||||||||||||||||||||||||||||||||||||||||
| size_t aie_pdi_bytes = static_cast<size_t>(aiep->aie_pdi.size) * sizeof(aie_pdi); | ||||||||||||||||||||||||||||||||||||||||
| if (aie_pdi_bytes > section_size || aiep->aie_pdi.offset > section_size - aie_pdi_bytes) | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+888
to
+895
|
||||||||||||||||||||||||||||||||||||||||
| size_t start_cols_bytes = static_cast<size_t>(aiep->info.start_columns.size) * sizeof(uint16_t); | |
| if (start_cols_bytes > section_size || | |
| aiep->info.start_columns.offset > section_size - start_cols_bytes) | |
| return {}; | |
| if (aiep->aie_pdi.offset >= section_size) | |
| return {}; | |
| size_t aie_pdi_bytes = static_cast<size_t>(aiep->aie_pdi.size) * sizeof(aie_pdi); | |
| if (aie_pdi_bytes > section_size || aiep->aie_pdi.offset > section_size - aie_pdi_bytes) | |
| if (aiep->info.start_columns.size > section_size / sizeof(uint16_t)) | |
| return {}; | |
| size_t start_cols_bytes = static_cast<size_t>(aiep->info.start_columns.size) * sizeof(uint16_t); | |
| if (aiep->info.start_columns.offset > section_size - start_cols_bytes) | |
| return {}; | |
| if (aiep->aie_pdi.offset >= section_size) | |
| return {}; | |
| if (aiep->aie_pdi.size > section_size / sizeof(aie_pdi)) | |
| return {}; | |
| size_t aie_pdi_bytes = static_cast<size_t>(aiep->aie_pdi.size) * sizeof(aie_pdi); | |
| if (aiep->aie_pdi.offset > section_size - aie_pdi_bytes) |
Copilot
AI
Feb 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These bounded reads prevent OOB, but can still copy very large substrings if the binary omits NUL terminators and the remaining section size is large. Consider adding a small maximum string length cap (like in tooling metadata) to avoid excessive allocations/copies from malformed inputs.
Copilot
AI
Feb 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Several size computations/offset+size checks are still overflow-prone with attacker-controlled values: multiplications like size * sizeof(T) can wrap, and additions like offset + size can wrap. Replace with overflow-safe comparisons (e.g., size > section_size / sizeof(T) before multiplying, and offset > section_size - size instead of offset + size > section_size) for start_cols_bytes, aie_pdi_bytes, cdo_groups_bytes, ids_bytes, and pdi_image.offset + pdi_image.size.
Copilot
AI
Feb 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Several size computations/offset+size checks are still overflow-prone with attacker-controlled values: multiplications like size * sizeof(T) can wrap, and additions like offset + size can wrap. Replace with overflow-safe comparisons (e.g., size > section_size / sizeof(T) before multiplying, and offset > section_size - size instead of offset + size > section_size) for start_cols_bytes, aie_pdi_bytes, cdo_groups_bytes, ids_bytes, and pdi_image.offset + pdi_image.size.
Copilot
AI
Feb 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These bounded reads prevent OOB, but can still copy very large substrings if the binary omits NUL terminators and the remaining section size is large. Consider adding a small maximum string length cap (like in tooling metadata) to avoid excessive allocations/copies from malformed inputs.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,5 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Licensed under the Apache License, Version 2.0 (the "License"). You may | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * not use this file except in compliance with the License. A copy of the | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -22,6 +21,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <boost/format.hpp> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <boost/functional/factory.hpp> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <boost/property_tree/json_parser.hpp> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <cstring> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| namespace XUtil = XclBinUtilities; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -37,9 +37,8 @@ SectionAIEResourcesBin::init::init() | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto sectionInfo = std::make_unique<SectionInfo>(AIE_RESOURCES_BIN, "AIE_RESOURCES_BIN", boost::factory<SectionAIEResourcesBin*>()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sectionInfo->supportsSubSections = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sectionInfo->subSections.push_back(getSubSectionName(SubSection::obj)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sectionInfo->subSections.push_back(getSubSectionName(SubSection::metadata)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sectionInfo->subSections.push_back(std::string(getSubSectionName(SubSection::obj))); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: use emplace_back instead of push_back [hicpp-use-emplace]
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sectionInfo->subSections.push_back(std::string(getSubSectionName(SubSection::metadata))); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: use emplace_back instead of push_back [hicpp-use-emplace]
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sectionInfo->supportsIndexing = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Add format support empty (no support) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -166,6 +165,13 @@ SectionAIEResourcesBin::copyBufferUpdateMetadata(const char* _pOrigDataSection, | |||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto pHdr = reinterpret_cast<const aie_resources_bin*>(_pOrigDataSection); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (pHdr->mpo_name >= _origSectionSize || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pHdr->mpo_version >= _origSectionSize || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pHdr->m_image_offset >= _origSectionSize || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (pHdr->m_image_offset + pHdr->m_image_size) > _origSectionSize) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw std::runtime_error("ERROR: Invalid offsets in aie_resources_bin structure"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
166
to
+173
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| XUtil::TRACE_BUF("aie_resources_bin-original", reinterpret_cast<const char*>(pHdr), sizeof(aie_resources_bin)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| XUtil::TRACE(boost::format("Original: \n" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| " mpo_name (0x%lx): '%s'\n" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -388,16 +394,19 @@ SectionAIEResourcesBin::writeObjImage(std::ostream& _oStream) const | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| XUtil::TRACE("SectionAIEResourcesBin::writeObjImage"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Overlay the structure | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Do we have enough room to overlay the header structure | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (m_bufferSize < sizeof(aie_resources_bin)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto errMsg = boost::format("ERROR: Segment size (%d) is smaller than the size of the bmc structure (%d)") % m_bufferSize % sizeof(aie_resources_bin); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw std::runtime_error(errMsg.str()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // No look at the data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto pHdr = reinterpret_cast<aie_resources_bin*>(m_pBuffer); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (pHdr->m_image_offset > m_bufferSize || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pHdr->m_image_size > m_bufferSize || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pHdr->m_image_offset > m_bufferSize - pHdr->m_image_size) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw std::runtime_error("ERROR: Invalid m_image_offset/m_image_size in aie_resources_bin"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto pFWBuffer = reinterpret_cast<const char*>(pHdr) + pHdr->m_image_offset; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _oStream.write(pFWBuffer, pHdr->m_image_size); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -409,38 +418,40 @@ SectionAIEResourcesBin::writeMetadata(std::ostream& _oStream) const | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| XUtil::TRACE("AIE_RESOURCES_BIN-METADATA"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Overlay the structure | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Do we have enough room to overlay the header structure | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (m_bufferSize < sizeof(aie_resources_bin)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto errMsg = boost::format("ERROR: Segment size (%d) is smaller than the size of the aie_resources_bin structure (%d)") % m_bufferSize % sizeof(aie_resources_bin); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw std::runtime_error(errMsg.str()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto pHdr = reinterpret_cast<aie_resources_bin*>(m_pBuffer); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto safe_str = [this, pHdr](uint32_t off) -> std::string { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (off >= m_bufferSize) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ""; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return std::string(reinterpret_cast<const char*>(pHdr) + off, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: avoid repeating the return type from the declaration; use a braced initializer list instead [modernize-return-braced-init-list] return std::string(reinterpret_cast<const char*>(pHdr) + off,
^ |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| strnlen(reinterpret_cast<const char*>(pHdr) + off, m_bufferSize - off)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
427
to
+432
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto safe_str = [this, pHdr](uint32_t off) -> std::string { | |
| if (off >= m_bufferSize) | |
| return ""; | |
| return std::string(reinterpret_cast<const char*>(pHdr) + off, | |
| strnlen(reinterpret_cast<const char*>(pHdr) + off, m_bufferSize - off)); | |
| const size_t kMaxMetadataStringLen = 4096; // Cap individual metadata strings to a reasonable size | |
| auto safe_str = [this, pHdr, kMaxMetadataStringLen](uint32_t off) -> std::string { | |
| if (off >= m_bufferSize) | |
| return ""; | |
| const char* ptr = reinterpret_cast<const char*>(pHdr) + off; | |
| size_t remaining = m_bufferSize - off; | |
| size_t maxSearch = (remaining > kMaxMetadataStringLen) ? kMaxMetadataStringLen : remaining; | |
| size_t len = strnlen(ptr, maxSearch); | |
| // If there is more data beyond the maximum allowed length and no terminator was found | |
| if (remaining > kMaxMetadataStringLen && len == maxSearch) { | |
| auto errMsg = boost::format("ERROR: Metadata string at offset 0x%lx exceeds maximum allowed length (%d bytes) or is unterminated") | |
| % static_cast<unsigned long>(off) % kMaxMetadataStringLen; | |
| throw std::runtime_error(errMsg.str()); | |
| } | |
| return std::string(ptr, len); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check
(soft->m_image_offset + soft->m_image_size) > section_sizecan be bypassed via unsigned integer overflow if the fields are file-controlled. Use an overflow-safe pattern instead (e.g., validatem_image_size <= section_sizeandm_image_offset <= section_size - m_image_size).