From 132e3e507d2ddababfe7892102e3386e394cf44c Mon Sep 17 00:00:00 2001 From: chaoticgd <43898262+chaoticgd@users.noreply.github.com> Date: Mon, 25 Nov 2024 06:40:41 +0000 Subject: [PATCH] 3rdparty/ccc: Fix some bounds checks and other error handling logic --- 3rdparty/ccc/src/ccc/elf.cpp | 17 +++++++------ 3rdparty/ccc/src/ccc/elf_symtab.cpp | 25 +++++++++--------- 3rdparty/ccc/src/ccc/mdebug_section.cpp | 22 ++++++++-------- 3rdparty/ccc/src/ccc/sndll.cpp | 22 ++++++++-------- 3rdparty/ccc/src/ccc/symbol_file.cpp | 4 +-- 3rdparty/ccc/src/ccc/util.cpp | 13 ++++++---- 3rdparty/ccc/src/ccc/util.h | 34 ++++++++++++++++++++----- 7 files changed, 83 insertions(+), 54 deletions(-) diff --git a/3rdparty/ccc/src/ccc/elf.cpp b/3rdparty/ccc/src/ccc/elf.cpp index 5bb11dd72c362..a8f3c0d72096c 100644 --- a/3rdparty/ccc/src/ccc/elf.cpp +++ b/3rdparty/ccc/src/ccc/elf.cpp @@ -10,34 +10,35 @@ Result ElfFile::parse(std::vector image) ElfFile elf; elf.image = std::move(image); - const ElfIdentHeader* ident = get_packed(elf.image, 0); + const ElfIdentHeader* ident = get_unaligned(elf.image, 0); CCC_CHECK(ident, "ELF ident header out of range."); CCC_CHECK(ident->magic == CCC_FOURCC("\x7f\x45\x4c\x46"), "Not an ELF file."); CCC_CHECK(ident->e_class == ElfIdentClass::B32, "Wrong ELF class (not 32 bit)."); - const ElfFileHeader* header = get_packed(elf.image, sizeof(ElfIdentHeader)); + const ElfFileHeader* header = get_unaligned(elf.image, sizeof(ElfIdentHeader)); CCC_CHECK(header, "ELF file header out of range."); elf.file_header = *header; - const ElfSectionHeader* shstr_section_header = get_packed(elf.image, header->shoff + header->shstrndx * sizeof(ElfSectionHeader)); + const ElfSectionHeader* shstr_section_header = + get_unaligned(elf.image, header->shoff + header->shstrndx * sizeof(ElfSectionHeader)); CCC_CHECK(shstr_section_header, "ELF section name header out of range."); for(u32 i = 0; i < header->shnum; i++) { u64 header_offset = header->shoff + i * sizeof(ElfSectionHeader); - const ElfSectionHeader* section_header = get_packed(elf.image, header_offset); + const ElfSectionHeader* section_header = get_unaligned(elf.image, header_offset); CCC_CHECK(section_header, "ELF section header out of range."); - const char* name = get_string(elf.image, shstr_section_header->offset + section_header->name); - CCC_CHECK(section_header, "ELF section name out of range."); + std::optional name = get_string(elf.image, shstr_section_header->offset + section_header->name); + CCC_CHECK(name.has_value(), "ELF section name out of range."); ElfSection& section = elf.sections.emplace_back(); - section.name = name; + section.name = *name; section.header = *section_header; } for(u32 i = 0; i < header->phnum; i++) { u64 header_offset = header->phoff + i * sizeof(ElfProgramHeader); - const ElfProgramHeader* program_header = get_packed(elf.image, header_offset); + const ElfProgramHeader* program_header = get_unaligned(elf.image, header_offset); CCC_CHECK(program_header, "ELF program header out of range."); elf.segments.emplace_back(*program_header); diff --git a/3rdparty/ccc/src/ccc/elf_symtab.cpp b/3rdparty/ccc/src/ccc/elf_symtab.cpp index 892ea5ec2d7e9..8432dc9fc3f06 100644 --- a/3rdparty/ccc/src/ccc/elf_symtab.cpp +++ b/3rdparty/ccc/src/ccc/elf_symtab.cpp @@ -60,7 +60,7 @@ Result import_symbols( DemanglerFunctions demangler) { for(u32 i = 0; i < symtab.size() / sizeof(Symbol); i++) { - const Symbol* symbol = get_packed(symtab, i * sizeof(Symbol)); + const Symbol* symbol = get_unaligned(symtab, i * sizeof(Symbol)); CCC_ASSERT(symbol); Address address; @@ -86,13 +86,14 @@ Result import_symbols( } } - const char* string = get_string(strtab, symbol->name); - CCC_CHECK(string, "Symbol string out of range."); + std::optional string_view = get_string(strtab, symbol->name); + CCC_CHECK(string_view.has_value(), "Symbol string out of range."); + std::string string(*string_view); switch(symbol->type()) { case SymbolType::NOTYPE: { Result label = database.labels.create_symbol( - string, group.source, group.module_symbol, address, importer_flags, demangler); + std::move(string), group.source, group.module_symbol, address, importer_flags, demangler); CCC_RETURN_IF_ERROR(label); // These symbols get emitted at the same addresses as functions @@ -108,7 +109,7 @@ Result import_symbols( case SymbolType::OBJECT: { if(symbol->size != 0) { Result global_variable = database.global_variables.create_symbol( - string, group.source, group.module_symbol, address, importer_flags, demangler); + std::move(string), group.source, group.module_symbol, address, importer_flags, demangler); CCC_RETURN_IF_ERROR(global_variable); if(*global_variable) { @@ -116,7 +117,7 @@ Result import_symbols( } } else { Result label = database.labels.create_symbol( - string, group.source, group.module_symbol, address, importer_flags, demangler); + std::move(string), group.source, group.module_symbol, address, importer_flags, demangler); CCC_RETURN_IF_ERROR(label); } @@ -124,7 +125,7 @@ Result import_symbols( } case SymbolType::FUNC: { Result function = database.functions.create_symbol( - string, group.source, group.module_symbol, address, importer_flags, demangler); + std::move(string), group.source, group.module_symbol, address, importer_flags, demangler); CCC_RETURN_IF_ERROR(function); if(*function) { @@ -135,7 +136,7 @@ Result import_symbols( } case SymbolType::FILE: { Result source_file = database.source_files.create_symbol( - string, group.source, group.module_symbol); + std::move(string), group.source, group.module_symbol); CCC_RETURN_IF_ERROR(source_file); break; @@ -153,18 +154,18 @@ Result print_symbol_table(FILE* out, std::span symtab, std::span fprintf(out, " Num: Value Size Type Bind Vis Ndx Name\n"); for(u32 i = 0; i < symtab.size() / sizeof(Symbol); i++) { - const Symbol* symbol = get_packed(symtab, i * sizeof(Symbol)); + const Symbol* symbol = get_unaligned(symtab, i * sizeof(Symbol)); CCC_ASSERT(symbol); const char* type = symbol_type_to_string(symbol->type()); const char* bind = symbol_bind_to_string(symbol->bind()); const char* visibility = symbol_visibility_to_string(symbol->visibility()); - const char* string = get_string(strtab, symbol->name); - CCC_CHECK(string, "Symbol string out of range."); + std::optional string = get_string(strtab, symbol->name); + CCC_CHECK(string.has_value(), "Symbol string out of range."); fprintf(out, "%6u: %08x %5u %-7s %-7s %-7s %3u %s\n", - i, symbol->value, symbol->size, type, bind, visibility, symbol->shndx, string); + i, symbol->value, symbol->size, type, bind, visibility, symbol->shndx, string->data()); } diff --git a/3rdparty/ccc/src/ccc/mdebug_section.cpp b/3rdparty/ccc/src/ccc/mdebug_section.cpp index 676303aad2b63..0745d0203f698 100644 --- a/3rdparty/ccc/src/ccc/mdebug_section.cpp +++ b/3rdparty/ccc/src/ccc/mdebug_section.cpp @@ -90,7 +90,7 @@ Result SymbolTableReader::init(std::span elf, s32 section_offset m_elf = elf; m_section_offset = section_offset; - m_hdrr = get_packed(m_elf, m_section_offset); + m_hdrr = get_unaligned(m_elf, m_section_offset); CCC_CHECK(m_hdrr != nullptr, "MIPS debug section header out of bounds."); CCC_CHECK(m_hdrr->magic == 0x7009, "Invalid symbolic header."); @@ -116,7 +116,7 @@ Result SymbolTableReader::parse_file(s32 index) const File file; u64 fd_offset = m_hdrr->file_descriptors_offset + index * sizeof(FileDescriptor); - const FileDescriptor* fd_header = get_packed(m_elf, fd_offset + m_fudge_offset); + const FileDescriptor* fd_header = get_unaligned(m_elf, fd_offset + m_fudge_offset); CCC_CHECK(fd_header != nullptr, "MIPS debug file descriptor out of bounds."); CCC_CHECK(fd_header->f_big_endian == 0, "Not little endian or bad file descriptor table."); @@ -124,16 +124,16 @@ Result SymbolTableReader::parse_file(s32 index) const s32 rel_raw_path_offset = fd_header->strings_offset + fd_header->file_path_string_offset; s32 raw_path_offset = m_hdrr->local_strings_offset + rel_raw_path_offset + m_fudge_offset; - const char* command_line_path = get_string(m_elf, raw_path_offset); - if(command_line_path) { - file.command_line_path = command_line_path; + std::optional command_line_path = get_string(m_elf, raw_path_offset); + if(command_line_path.has_value()) { + file.command_line_path = *command_line_path; } // Parse local symbols. for(s64 j = 0; j < fd_header->symbol_count; j++) { u64 rel_symbol_offset = (fd_header->isym_base + j) * sizeof(SymbolHeader); u64 symbol_offset = m_hdrr->local_symbols_offset + rel_symbol_offset + m_fudge_offset; - const SymbolHeader* symbol_header = get_packed(m_elf, symbol_offset); + const SymbolHeader* symbol_header = get_unaligned(m_elf, symbol_offset); CCC_CHECK(symbol_header != nullptr, "Symbol header out of bounds."); s32 strings_offset = m_hdrr->local_strings_offset + fd_header->strings_offset + m_fudge_offset; @@ -155,7 +155,7 @@ Result SymbolTableReader::parse_file(s32 index) const for(s64 i = 0; i < fd_header->procedure_descriptor_count; i++) { u64 rel_procedure_offset = (fd_header->ipd_first + i) * sizeof(ProcedureDescriptor); u64 procedure_offset = m_hdrr->procedure_descriptors_offset + rel_procedure_offset + m_fudge_offset; - const ProcedureDescriptor* procedure_descriptor = get_packed(m_elf, procedure_offset); + const ProcedureDescriptor* procedure_descriptor = get_unaligned(m_elf, procedure_offset); CCC_CHECK(procedure_descriptor != nullptr, "Procedure descriptor out of bounds."); CCC_CHECK(procedure_descriptor->symbol_index < file.symbols.size(), "Symbol index out of bounds."); @@ -175,7 +175,7 @@ Result> SymbolTableReader::parse_external_symbols() const std::vector external_symbols; for(s64 i = 0; i < m_hdrr->external_symbols_count; i++) { u64 sym_offset = m_hdrr->external_symbols_offset + i * sizeof(ExternalSymbolHeader); - const ExternalSymbolHeader* external_header = get_packed(m_elf, sym_offset + m_fudge_offset); + const ExternalSymbolHeader* external_header = get_unaligned(m_elf, sym_offset + m_fudge_offset); CCC_CHECK(external_header != nullptr, "External header out of bounds."); Result sym = get_symbol(external_header->symbol, m_elf, m_hdrr->external_strings_offset + m_fudge_offset); @@ -351,9 +351,9 @@ static Result get_symbol(const SymbolHeader& header, std::span { Symbol symbol; - const char* string = get_string(elf, strings_offset + header.iss); - CCC_CHECK(string, "Symbol has invalid string."); - symbol.string = string; + std::optional string = get_string(elf, strings_offset + header.iss); + CCC_CHECK(string.has_value(), "Symbol has invalid string."); + symbol.string = string->data(); symbol.value = header.value; symbol.symbol_type = (SymbolType) header.st; diff --git a/3rdparty/ccc/src/ccc/sndll.cpp b/3rdparty/ccc/src/ccc/sndll.cpp index 894deba69efb9..52a3654f52b8a 100644 --- a/3rdparty/ccc/src/ccc/sndll.cpp +++ b/3rdparty/ccc/src/ccc/sndll.cpp @@ -54,18 +54,19 @@ static const char* sndll_symbol_type_to_string(SNDLLSymbolType type); Result parse_sndll_file(std::span image, Address address, SNDLLType type) { - const u32* magic = get_packed(image, 0); + std::optional magic = copy_unaligned(image, 0); + CCC_CHECK(magic.has_value(), "Failed to read SNDLL header."); CCC_CHECK((*magic & 0xffffff) == CCC_FOURCC("SNR\00"), "Not a SNDLL %s.", address.valid() ? "section" : "file"); char version = *magic >> 24; switch(version) { case '1': { - const SNDLLHeaderV1* header = get_packed(image, 0); + const SNDLLHeaderV1* header = get_unaligned(image, 0); CCC_CHECK(header, "File too small to contain SNDLL V1 header."); return parse_sndll_common(image, address, type, header->common, SNDLL_V1); } case '2': { - const SNDLLHeaderV2* header = get_packed(image, 0); + const SNDLLHeaderV2* header = get_unaligned(image, 0); CCC_CHECK(header, "File too small to contain SNDLL V2 header."); return parse_sndll_common(image, address, type, header->common, SNDLL_V2); } @@ -84,10 +85,9 @@ static Result parse_sndll_common( sndll.version = version; if(common.elf_path) { - const char* elf_path = get_string(image, common.elf_path); - if(elf_path) { - sndll.elf_path = elf_path; - } + std::optional elf_path = get_string(image, common.elf_path); + CCC_CHECK(elf_path.has_value(), "SNDLL header has invalid ELF path field."); + sndll.elf_path = *elf_path; } CCC_CHECK(common.symbol_count < (32 * 1024 * 1024) / sizeof(SNDLLSymbol), "SNDLL symbol count is too high."); @@ -95,10 +95,10 @@ static Result parse_sndll_common( for(u32 i = 0; i < common.symbol_count; i++) { u32 symbol_offset = common.symbols - address.get_or_zero() + i * sizeof(SNDLLSymbolHeader); - const SNDLLSymbolHeader* symbol_header = get_packed(image, symbol_offset); + const SNDLLSymbolHeader* symbol_header = get_unaligned(image, symbol_offset); CCC_CHECK(symbol_header, "SNDLL symbol out of range."); - const char* string = nullptr; + std::optional string; if(symbol_header->string) { string = get_string(image, symbol_header->string - address.get_or_zero()); } @@ -106,7 +106,9 @@ static Result parse_sndll_common( SNDLLSymbol& symbol = sndll.symbols.emplace_back(); symbol.type = symbol_header->type; symbol.value = symbol_header->value; - symbol.string = string; + if(string.has_value()) { + symbol.string = *string; + } } return sndll; diff --git a/3rdparty/ccc/src/ccc/symbol_file.cpp b/3rdparty/ccc/src/ccc/symbol_file.cpp index d645926ac7799..54f9dfcb4c1a7 100644 --- a/3rdparty/ccc/src/ccc/symbol_file.cpp +++ b/3rdparty/ccc/src/ccc/symbol_file.cpp @@ -7,8 +7,8 @@ namespace ccc { Result> parse_symbol_file(std::vector image, std::string file_name) { - const u32* magic = get_packed(image, 0); - CCC_CHECK(magic, "File too small."); + const std::optional magic = copy_unaligned(image, 0); + CCC_CHECK(magic.has_value(), "File too small."); std::unique_ptr symbol_file; diff --git a/3rdparty/ccc/src/ccc/util.cpp b/3rdparty/ccc/src/ccc/util.cpp index a16d9c56c1f07..80ef27973d39c 100644 --- a/3rdparty/ccc/src/ccc/util.cpp +++ b/3rdparty/ccc/src/ccc/util.cpp @@ -51,14 +51,17 @@ void set_custom_error_callback(CustomErrorCallback callback) custom_error_callback = callback; } -const char* get_string(std::span bytes, u64 offset) +std::optional get_string(std::span bytes, u64 offset) { - for(const unsigned char* c = bytes.data() + offset; c < bytes.data() + bytes.size(); c++) { - if(*c == '\0') { - return (const char*) &bytes[offset]; + for(u64 i = offset; i < bytes.size(); i++) { + if(bytes[i] == '\0') { + return std::string_view( + reinterpret_cast(&bytes[offset]), + reinterpret_cast(&bytes[i])); } } - return nullptr; + + return std::nullopt; } std::string merge_paths(const std::string& base, const std::string& path) diff --git a/3rdparty/ccc/src/ccc/util.h b/3rdparty/ccc/src/ccc/util.h index ac27d7e2a0785..0be452def8085 100644 --- a/3rdparty/ccc/src/ccc/util.h +++ b/3rdparty/ccc/src/ccc/util.h @@ -72,7 +72,7 @@ void set_custom_error_callback(CustomErrorCallback callback); } #define CCC_ABORT_IF_FALSE(condition, ...) \ - if (!(condition)) { \ + if(!(condition)) { \ ccc::Error error = ccc::format_error(__FILE__, __LINE__, __VA_ARGS__); \ ccc::report_error(error); \ abort(); \ @@ -208,16 +208,38 @@ void warn_impl(const char* source_file, int source_line, const char* format, Arg #endif template -const T* get_packed(std::span bytes, u64 offset) +const T* get_aligned(std::span bytes, u64 offset) +{ + if(offset > bytes.size() || bytes.size() - offset < sizeof(T) || offset % alignof(T) != 0) { + return nullptr; + } + + return reinterpret_cast(&bytes[offset]); +} + +template +const T* get_unaligned(std::span bytes, u64 offset) { - if(offset + sizeof(T) <= bytes.size()) { - return reinterpret_cast(&bytes[offset]); - } else { + if(offset > bytes.size() || bytes.size() - offset < sizeof(T)) { return nullptr; } + + return reinterpret_cast(&bytes[offset]); +} + +template +std::optional copy_unaligned(std::span bytes, u64 offset) +{ + if(offset > bytes.size() || bytes.size() - offset < sizeof(T)) { + return std::nullopt; + } + + T value; + memcpy(&value, &bytes[offset], sizeof(T)); + return value; } -const char* get_string(std::span bytes, u64 offset); +std::optional get_string(std::span bytes, u64 offset); #define CCC_BEGIN_END(x) (x).begin(), (x).end() #define CCC_ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))