diff --git a/src/runtime_src/core/common/api/elf_patcher.cpp b/src/runtime_src/core/common/api/elf_patcher.cpp index 200be2e0578..ed4e3e1474d 100644 --- a/src/runtime_src/core/common/api/elf_patcher.cpp +++ b/src/runtime_src/core/common/api/elf_patcher.cpp @@ -4,6 +4,7 @@ #define XCL_DRIVER_DLL_EXPORT // in same dll as xrt_api #define XRT_CORE_COMMON_SOURCE // in same dll as core_common #include "elf_patcher.h" +#include "core/common/error.h" #include #include @@ -11,6 +12,42 @@ namespace xrt_core::elf_patcher { +// Return the minimum number of bytes required past bd_data_ptr for a given symbol type. +// Used to bounds-check the patch offset before any pointer arithmetic. +static size_t +required_patch_bytes(symbol_type type) +{ + switch (type) { + case symbol_type::address_64: + // words [0],[1] + return 2 * sizeof(uint32_t); // NOLINT(readability-magic-numbers) + case symbol_type::scalar_32bit_kind: + // word [0] + return 1 * sizeof(uint32_t); // NOLINT(readability-magic-numbers) + case symbol_type::shim_dma_base_addr_symbol_kind: + // words [1],[2],[8] — buffer must cover indices [0..8] + return 9 * sizeof(uint32_t); // NOLINT(readability-magic-numbers) + case symbol_type::shim_dma_aie4_base_addr_symbol_kind: + // words [0],[1] + return 2 * sizeof(uint32_t); // NOLINT(readability-magic-numbers) + case symbol_type::control_packet_57: + case symbol_type::control_packet_48: + // words [2],[3] — buffer must cover indices [0..3] + return 4 * sizeof(uint32_t); // NOLINT(readability-magic-numbers) + case symbol_type::shim_dma_48: + // words [1],[2] — buffer must cover indices [0..2] + return 3 * sizeof(uint32_t); // NOLINT(readability-magic-numbers) + case symbol_type::control_packet_57_aie4: + // words [1],[2] — buffer must cover indices [0..2] + return 3 * sizeof(uint32_t); // NOLINT(readability-magic-numbers) + case symbol_type::pl_ddr_64: + // words [8],[9] — buffer must cover indices [0..9] + return 10 * sizeof(uint32_t); // NOLINT(readability-magic-numbers) + default: + return 0; + } +} + // Get AIE DDR address offset inline static uint64_t get_ddr_aie_addr_offset() @@ -174,6 +211,7 @@ patch_symbol(xrt::bo bo, uint64_t value, bool first, bool is_arg) throw std::runtime_error("symbol_patcher: config not set"); auto base = reinterpret_cast(bo.map()); + auto bo_size = bo.size(); const auto& configs = m_config->m_patch_configs; // Ensure runtime state is properly sized @@ -185,6 +223,10 @@ patch_symbol(xrt::bo bo, uint64_t value, bool first, bool is_arg) auto& state = m_states[i]; auto offset = config.offset_to_patch_buffer; + auto patch_bytes = required_patch_bytes(m_config->m_symbol_type); + if (offset > bo_size || patch_bytes > bo_size - offset) + throw xrt_core::error(-EINVAL, "ELF patch offset exceeds instruction buffer"); + auto bd_data_ptr = reinterpret_cast(base + offset); // If the symbol patched is an argument to kernel we have to cache @@ -203,88 +245,62 @@ patch_symbol(xrt::bo bo, uint64_t value, bool first, bool is_arg) } } - // lambda for calling sync bo - // We only sync the words that are patched not the entire bo - auto sync = [&](size_t size) { - bo.sync(XCL_BO_SYNC_BO_TO_DEVICE, size, offset); + // Sync the patched words back to device. patch_bytes bytes from offset covers + // exactly the words touched by each patch function — same value used for + // the bounds check above, so no size argument is needed here. + auto sync = [&]() { + bo.sync(XCL_BO_SYNC_BO_TO_DEVICE, patch_bytes, offset); }; switch (m_config->m_symbol_type) { case symbol_type::address_64: - // value is a 64bit address patch64(bd_data_ptr, value); - if (!first) { - // sync 64 bits patched - sync(sizeof(uint64_t)); - } + if (!first) + sync(); break; case symbol_type::scalar_32bit_kind: - // value is a register value if (config.mask) { patch32(bd_data_ptr, value, config.mask); - if (!first) { - // sync 32 bits patched - sync(sizeof(uint32_t)); - } + if (!first) + sync(); } break; case symbol_type::shim_dma_base_addr_symbol_kind: - // value is a bo address patch57(bd_data_ptr, value + config.offset_to_base_bo_addr); - if (!first) { - // sync all the words (max_bd_words) - sync(sizeof(uint32_t) * max_bd_words); - } + if (!first) + sync(); break; case symbol_type::shim_dma_aie4_base_addr_symbol_kind: - // value is a bo address patch57_aie4(bd_data_ptr, value + config.offset_to_base_bo_addr); - if (!first) { - // sync 64 bits or 2 words - sync(sizeof(uint64_t)); - } + if (!first) + sync(); break; case symbol_type::control_packet_57: - // value is a bo address patch_ctrl57(bd_data_ptr, value + config.offset_to_base_bo_addr); - if (!first) { - // Data in this case is written till 3rd offset of bd_data_ptr - // so syncing 4 words - sync(4 * sizeof(uint32_t)); // NOLINT - } + if (!first) + sync(); break; case symbol_type::control_packet_48: - // value is a bo address patch_ctrl48(bd_data_ptr, value + config.offset_to_base_bo_addr); - if (!first) { - // Data in this case is written till 3rd offset of bd_data_ptr - // so syncing 4 words - sync(4 * sizeof(uint32_t)); // NOLINT - } + if (!first) + sync(); break; case symbol_type::shim_dma_48: - // value is a bo address patch_shim48(bd_data_ptr, value + config.offset_to_base_bo_addr); - if (!first) { - // syncing 3 words - sync(3 * sizeof(uint32_t)); // NOLINT - } + if (!first) + sync(); break; case symbol_type::control_packet_57_aie4: - // value is a bo address patch_ctrl57_aie4(bd_data_ptr, value + config.offset_to_base_bo_addr); - if (!first) { - // syncing 3 words - sync(3 * sizeof(uint32_t)); // NOLINT - } + if (!first) + sync(); break; case symbol_type::pl_ddr_64: - // value is a bo address; patch words [8]+[9] of wts_params block + // words [8]+[9]: sync only those 2 words at their position within the block; + // the bounds check above (patch_bytes= 10 words) already covers this sub-range. patch_pl_ddr64(bd_data_ptr, value + config.offset_to_base_bo_addr); - if (!first) { - // sync words [8] and [9] (2 words starting at offset + 8*sizeof(uint32_t)) + if (!first) bo.sync(XCL_BO_SYNC_BO_TO_DEVICE, 2 * sizeof(uint32_t), offset + 8 * sizeof(uint32_t)); // NOLINT - } break; default: throw std::runtime_error("Unsupported symbol type"); @@ -294,10 +310,13 @@ patch_symbol(xrt::bo bo, uint64_t value, bool first, bool is_arg) void symbol_patcher:: -patch_symbol_raw(uint8_t* base, uint64_t value, const patcher_config& config) +patch_symbol_raw(uint8_t* base, size_t buf_size, uint64_t value, const patcher_config& config) { for (const auto& cfg : config.m_patch_configs) { auto offset = cfg.offset_to_patch_buffer; + auto patch_bytes = required_patch_bytes(config.m_symbol_type); + if (offset > buf_size || patch_bytes > buf_size - offset) + throw xrt_core::error(-EINVAL, "ELF patch offset exceeds instruction buffer"); auto bd_data_ptr = reinterpret_cast(base + offset); // NOLINT switch (config.m_symbol_type) { diff --git a/src/runtime_src/core/common/api/elf_patcher.h b/src/runtime_src/core/common/api/elf_patcher.h index a4ec66eb95d..e03eee4686f 100644 --- a/src/runtime_src/core/common/api/elf_patcher.h +++ b/src/runtime_src/core/common/api/elf_patcher.h @@ -150,8 +150,9 @@ struct symbol_patcher // static method for patching raw buffers passed by shim tests // where the caller handles sync themselves // It patches directly using config without maintaining state. + // buf_size is the total size of the buffer pointed to by base. static void - patch_symbol_raw(uint8_t* base, uint64_t value, const patcher_config& config); + patch_symbol_raw(uint8_t* base, size_t buf_size, uint64_t value, const patcher_config& config); private: // Different patching functions for different symbol types. diff --git a/src/runtime_src/core/common/api/xrt_module.cpp b/src/runtime_src/core/common/api/xrt_module.cpp index d1e3c6cd6ad..67c48a77963 100644 --- a/src/runtime_src/core/common/api/xrt_module.cpp +++ b/src/runtime_src/core/common/api/xrt_module.cpp @@ -1413,7 +1413,7 @@ patch(const xrt::module& module, uint8_t* ibuf, size_t sz, } // Use static patch method (no state needed for shim tests) - xrt_core::elf_patcher::symbol_patcher::patch_symbol_raw(ibuf, arg_addr, it->second); + xrt_core::elf_patcher::symbol_patcher::patch_symbol_raw(ibuf, sz, arg_addr, it->second); index++; } }