Added new check for section/progHeader consistency

This commit is contained in:
Martin Bickel 2021-01-05 17:50:23 +01:00 committed by Serge Lamikhov-Center
parent def3653abc
commit 3e55690e6d
3 changed files with 85 additions and 17 deletions

View File

@ -251,30 +251,72 @@ class elfio
( offset < ( sec->get_offset() + sec->get_size() ) ); ( offset < ( sec->get_offset() + sec->get_size() ) );
} }
Elf64_Addr get_virtual_addr( Elf64_Off offset, const section* sec ) const
{
return sec->get_address() + offset - sec->get_offset();
}
const section* find_prog_section_for_offset( Elf64_Off offset ) const
{
for ( int i = 0; i < sections.size(); ++i ) {
const section* sec = sections[i];
if ( sec->get_type() == SHT_PROGBITS )
if ( is_offset_in_section( offset, sec ) )
return sec;
}
return NULL;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
public: public:
//! returns an empty string if no problems are detected, //! returns an empty string if no problems are detected,
//! or a string containing an error message if problems are found //! or a string containing an error message if problems are found,
//! with one error per line.
std::string validate() const std::string validate() const
{ {
// clang-format off
// check for overlapping sections in the file std::string errors;
for ( int i = 0; i < sections.size(); ++i ) { // Check for overlapping sections in the file
for ( int j = i + 1; j < sections.size(); ++j ) { // This is explicitly forbidden by ELF specification
for ( int i = 0; i < sections.size(); ++i) {
for ( int j = i+1; j < sections.size(); ++j ) {
const section* a = sections[i]; const section* a = sections[i];
const section* b = sections[j]; const section* b = sections[j];
if ( !( a->get_type() & SHT_NOBITS ) && if ( !(a->get_type() & SHT_NOBITS)
!( b->get_type() & SHT_NOBITS ) && ( a->get_size() > 0 ) && && !(b->get_type() & SHT_NOBITS)
( b->get_size() > 0 ) && ( a->get_offset() > 0 ) && && (a->get_size() > 0)
( b->get_offset() > 0 ) ) { && (b->get_size() > 0)
if ( is_offset_in_section( a->get_offset(), b ) || && (a->get_offset() > 0)
is_offset_in_section( && (b->get_offset() > 0)) {
a->get_offset() + a->get_size() - 1, b ) || if ( is_offset_in_section( a->get_offset(), b )
is_offset_in_section( b->get_offset(), a ) || || is_offset_in_section( a->get_offset()+a->get_size()-1, b )
is_offset_in_section( || is_offset_in_section( b->get_offset(), a )
b->get_offset() + b->get_size() - 1, a ) ) { || is_offset_in_section( b->get_offset()+b->get_size()-1, a )) {
return "Sections " + a->get_name() + " and " + errors += "Sections " + a->get_name() + " and " + b->get_name() + " overlap in file\n";
b->get_name() + " overlap in file"; }
}
}
}
// Check for conflicting section / program header tables, where
// the same offset has different vaddresses in section table and
// program header table.
// This doesn't seem to be explicitly forbidden by ELF specification,
// but:
// - it doesn't make any sense
// - ELFIO relies on this being consistent when writing ELF files,
// since offsets are re-calculated from vaddress
for ( int h = 0; h < segments.size(); ++h ) {
const segment* seg = segments[h];
if ( seg->get_type() == PT_LOAD && seg->get_file_size() > 0 ) {
auto sec = find_prog_section_for_offset( seg->get_offset() );
if ( sec ) {
auto sec_addr = get_virtual_addr( seg->get_offset(), sec );
if ( sec_addr != seg->get_virtual_address() ) {
errors += "Virtual address of segment " + std::to_string( h ) + " (" + to_hex_string( seg->get_virtual_address() ) + ")"
+ " conflicts with address of section " + sec->get_name() + " (" + to_hex_string( sec_addr ) + ")"
+ " at offset " + to_hex_string( seg->get_offset() ) + "\n";
} }
} }
} }
@ -282,7 +324,8 @@ class elfio
// more checks to be added here... // more checks to be added here...
return ""; return errors;
// clang-format on
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -172,6 +172,21 @@ inline uint32_t elf_hash( const unsigned char* name )
return h; return h;
} }
inline std::string to_hex_string( Elf64_Addr t )
{
std::string s;
while( t ) {
auto d = t & 0xf;
if ( d < 0xa )
s = char('0' + d) + s;
else
s = char('A' + d - 0xa) + s;
t >>= 4;
}
return "0x" + s;
}
} // namespace ELFIO } // namespace ELFIO
#endif // ELFIO_UTILS_HPP #endif // ELFIO_UTILS_HPP

View File

@ -232,3 +232,13 @@ BOOST_AUTO_TEST_CASE( init_array_write_64 )
BOOST_CHECK_EQUAL( array.get_entry( 2, addr ), true ); BOOST_CHECK_EQUAL( array.get_entry( 2, addr ), true );
BOOST_CHECK_EQUAL( addr, 0x12345678 ); BOOST_CHECK_EQUAL( addr, 0x12345678 );
} }
////////////////////////////////////////////////////////////////////////////////
BOOST_AUTO_TEST_CASE( test_hex )
{
BOOST_CHECK_EQUAL( to_hex_string( 1 ), "0x1");
BOOST_CHECK_EQUAL( to_hex_string( 10 ), "0xA");
BOOST_CHECK_EQUAL( to_hex_string( 0x12345678 ), "0x12345678");
BOOST_CHECK_EQUAL( to_hex_string( 0xFFFFFFFF ), "0xFFFFFFFF");
BOOST_CHECK_EQUAL( to_hex_string( 0xFFFFFFFFFFFFFFFF ), "0xFFFFFFFFFFFFFFFF");
}