Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
220 changes: 220 additions & 0 deletions patches/third-party/elfio/0002-Validate-note-accessor-bounds.patch
Original file line number Diff line number Diff line change
@@ -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 <cstring>
+
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<char*>( 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<char*>( 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<size_t>( 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<Elf_Xword>( 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<Elf_Xword> note_start_positions;
+ Elf_Xword scanned_size = 0; // End of the records decoded by the last scan
};

using note_section_accessor =
Loading