diff --git a/patches/third-party/elfio/0002-Validate-note-accessor-bounds.patch b/patches/third-party/elfio/0002-Validate-note-accessor-bounds.patch new file mode 100644 index 00000000000..33a56382a2f --- /dev/null +++ b/patches/third-party/elfio/0002-Validate-note-accessor-bounds.patch @@ -0,0 +1,220 @@ +Subject: [PATCH] Update ELFIO note parsing + +Backport the upstream note accessor updates to ELFIO 3.12. Share record +decoding between scanning and lookup, preserve nameless notes and notes +whose owner name lacks a terminator, keep output parameters unchanged when +a record cannot be read, and keep notes added with add_note() aligned and +consistently indexed. + +Upstream: https://github.com/serge1/ELFIO/pull/173 +JIRA: SWSPLAT-24318 + +Remove this backport when updating to a release that includes these changes. + +diff --git a/elfio/elfio_note.hpp b/elfio/elfio_note.hpp +index 63ef102..6c1adc4 100644 +--- a/elfio/elfio_note.hpp ++++ b/elfio/elfio_note.hpp +@@ -23,6 +23,8 @@ THE SOFTWARE. + #ifndef ELFIO_NOTE_HPP + #define ELFIO_NOTE_HPP + ++#include ++ + namespace ELFIO { + + //------------------------------------------------------------------------------ +@@ -62,34 +64,23 @@ class note_section_accessor_template + char*& desc, + Elf_Word& descSize ) const + { +- if ( index >= ( notes->*F_get_size )() ) { ++ if ( index >= note_start_positions.size() ) { + return false; + } + +- const char* pData = notes->get_data() + note_start_positions[index]; +- int align = sizeof( Elf_Word ); +- +- const endianess_convertor& convertor = elf_file.get_convertor(); +- type = convertor( *(const Elf_Word*)( pData + 2 * (size_t)align ) ); +- Elf_Word namesz = convertor( *(const Elf_Word*)( pData ) ); +- descSize = convertor( *(const Elf_Word*)( pData + sizeof( namesz ) ) ); +- +- Elf_Xword max_name_size = +- ( notes->*F_get_size )() - note_start_positions[index]; +- if ( namesz < 1 || namesz > max_name_size || +- (Elf_Xword)namesz + descSize > max_name_size ) { ++ const char* data = notes->get_data(); ++ const Elf_Xword data_size = ( notes->*F_get_size )(); ++ note_record record; ++ // The section may have changed since its note offsets were collected. ++ if ( !read_note( data, data_size, note_start_positions[index], ++ record ) ) { + return false; + } +- name.assign( pData + 3 * (size_t)align, namesz - 1 ); +- if ( 0 == descSize ) { +- desc = nullptr; +- } +- else { +- desc = const_cast( pData + 3 * (size_t)align + +- ( ( namesz + align - 1 ) / align ) * +- (size_t)align ); +- } + ++ name.assign( record.name, record.name_size ); ++ type = record.type; ++ descSize = record.descriptor_size; ++ desc = const_cast( record.descriptor ); + return true; + } + +@@ -101,6 +92,11 @@ class note_section_accessor_template + { + const endianess_convertor& convertor = elf_file.get_convertor(); + ++ // A record without descriptor data must not claim a descriptor ++ if ( desc == nullptr ) { ++ descSize = 0; ++ } ++ + int align = sizeof( Elf_Word ); + Elf_Word nameLen = (Elf_Word)name.size() + 1; + Elf_Word nameLenConv = convertor( nameLen ); +@@ -123,44 +119,99 @@ class note_section_accessor_template + } + } + +- note_start_positions.emplace_back( ( notes->*F_get_size )() ); +- notes->append_data( buffer ); ++ // Records start on a 4-byte boundary, even when the existing data ++ // does not end on one ++ constexpr Elf_Xword word_size = sizeof( Elf_Word ); ++ const Elf_Xword current_size = ( notes->*F_get_size )(); ++ const Elf_Xword padding = ++ ( word_size - current_size % word_size ) % word_size; ++ notes->append_data( ++ std::string( static_cast( padding ), '\0' ) + buffer ); ++ if ( current_size == scanned_size ) { ++ // The existing data decoded completely, so the new record simply ++ // follows it ++ note_start_positions.emplace_back( current_size ); ++ scanned_size = current_size + buffer.size(); ++ } ++ else { ++ // The appended bytes may complete a record the scan stopped at, so ++ // rescan to keep indices consistent with a fresh accessor ++ process_section(); ++ } + } + + private: +- //------------------------------------------------------------------------------ +- void process_section() ++ struct note_record + { +- const endianess_convertor& convertor = elf_file.get_convertor(); +- const char* data = notes->get_data(); +- Elf_Xword size = ( notes->*F_get_size )(); +- Elf_Xword current = 0; ++ Elf_Word type; ++ const char* name; ++ Elf_Word name_size; ++ const char* descriptor; ++ Elf_Word descriptor_size; ++ Elf_Xword total_size; ++ }; ++ ++ static Elf_Xword padded_size( Elf_Word size ) ++ { ++ constexpr Elf_Xword alignment = sizeof( Elf_Word ); ++ return ( static_cast( size ) + alignment - 1 ) / alignment * ++ alignment; ++ } + +- note_start_positions.clear(); ++ // Decode one complete record. Scanning and lookup share these checks. ++ bool read_note( const char* data, ++ Elf_Xword data_size, ++ Elf_Xword position, ++ note_record& record ) const ++ { ++ constexpr Elf_Xword header_size = 3 * sizeof( Elf_Word ); ++ if ( data == nullptr || position > data_size || ++ header_size > data_size - position ) { ++ return false; ++ } + +- // Is it empty? +- if ( nullptr == data || 0 == size ) { +- return; ++ Elf_Word header[3]; ++ std::memcpy( header, data + position, sizeof( header ) ); ++ const auto& convertor = elf_file.get_convertor(); ++ const Elf_Word namesz = convertor( header[0] ); ++ const Elf_Word descsz = convertor( header[1] ); ++ const Elf_Xword padded_name = padded_size( namesz ); ++ const Elf_Xword padded_desc = padded_size( descsz ); ++ const Elf_Xword remaining = data_size - position - header_size; ++ if ( padded_name > remaining || ++ padded_desc > remaining - padded_name ) { ++ return false; + } + +- Elf_Word align = sizeof( Elf_Word ); +- while ( current + (Elf_Xword)3 * align <= size ) { +- Elf_Word namesz = convertor( *(const Elf_Word*)( data + current ) ); +- Elf_Word descsz = convertor( +- *(const Elf_Word*)( data + current + sizeof( namesz ) ) ); +- Elf_Word advance = +- (Elf_Xword)3 * sizeof( Elf_Word ) + +- ( ( namesz + align - 1 ) / align ) * (Elf_Xword)align + +- ( ( descsz + align - 1 ) / align ) * (Elf_Xword)align; +- if ( namesz < size && descsz < size && current + advance <= size ) { +- note_start_positions.emplace_back( current ); +- } +- else { +- break; +- } ++ const char* name = data + position + header_size; ++ // Some producers omit the owner's terminator; keep the full name then ++ const bool terminated = namesz != 0 && name[namesz - 1] == '\0'; ++ record.type = convertor( header[2] ); ++ record.name = name; ++ record.name_size = terminated ? namesz - 1 : namesz; ++ record.descriptor = descsz == 0 ? nullptr : name + padded_name; ++ record.descriptor_size = descsz; ++ record.total_size = header_size + padded_name + padded_desc; ++ return true; ++ } + +- current += advance; ++ //------------------------------------------------------------------------------ ++ void process_section() ++ { ++ note_start_positions.clear(); ++ scanned_size = 0; ++ if ( notes == nullptr ) { ++ return; ++ } ++ const char* data = notes->get_data(); ++ const Elf_Xword data_size = ( notes->*F_get_size )(); ++ Elf_Xword current = 0; ++ note_record record; ++ while ( read_note( data, data_size, current, record ) ) { ++ note_start_positions.emplace_back( current ); ++ current += record.total_size; + } ++ scanned_size = current; + } + + //------------------------------------------------------------------------------ +@@ -168,6 +219,7 @@ class note_section_accessor_template + const elfio& elf_file; + S* notes; + std::vector note_start_positions; ++ Elf_Xword scanned_size = 0; // End of the records decoded by the last scan + }; + + using note_section_accessor =