From 6e237576f0e3a409e04c3bf9f131421b5c0912e2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pierre=20B=C3=A9lissent?=
 <belissent@users.noreply.github.com>
Date: Sat, 6 Jun 2020 21:16:44 +0200
Subject: [PATCH] Issue serge1/ELFIO#19: Test case to reproduce, and correction

---
 ELFIOTest/ELFIOTest1.cpp | 123 ++++++++++++++++++++++++++++++---------
 elfio/elfio.hpp          |   4 +-
 2 files changed, 97 insertions(+), 30 deletions(-)

diff --git a/ELFIOTest/ELFIOTest1.cpp b/ELFIOTest/ELFIOTest1.cpp
index efb49e0..8a254ba 100644
--- a/ELFIOTest/ELFIOTest1.cpp
+++ b/ELFIOTest/ELFIOTest1.cpp
@@ -26,15 +26,15 @@ bool write_obj_i386( bool is64bit )
     text_sec->set_type( SHT_PROGBITS );
     text_sec->set_flags( SHF_ALLOC | SHF_EXECINSTR );
     text_sec->set_addr_align( 0x10 );
-    
+
     // Add data into it
-    char text[] = { '\xB8', '\x04', '\x00', '\x00', '\x00',   // mov eax, 4		      
-                    '\xBB', '\x01', '\x00', '\x00', '\x00',   // mov ebx, 1		      
-                    '\xB9', '\x00', '\x00', '\x00', '\x00',   // mov ecx, msg		      
-                    '\xBA', '\x0E', '\x00', '\x00', '\x00',   // mov edx, 14		      
-                    '\xCD', '\x80',                           // int 0x80		      
-                    '\xB8', '\x01', '\x00', '\x00', '\x00',   // mov eax, 1		      
-                    '\xCD', '\x80'                            // int 0x80		      
+    char text[] = { '\xB8', '\x04', '\x00', '\x00', '\x00',   // mov eax, 4
+                    '\xBB', '\x01', '\x00', '\x00', '\x00',   // mov ebx, 1
+                    '\xB9', '\x00', '\x00', '\x00', '\x00',   // mov ecx, msg
+                    '\xBA', '\x0E', '\x00', '\x00', '\x00',   // mov edx, 14
+                    '\xCD', '\x80',                           // int 0x80
+                    '\xB8', '\x01', '\x00', '\x00', '\x00',   // mov eax, 1
+                    '\xCD', '\x80'                            // int 0x80
                   };
     text_sec->set_data( text, sizeof( text ) );
 
@@ -43,7 +43,7 @@ bool write_obj_i386( bool is64bit )
     data_sec->set_type( SHT_PROGBITS );
     data_sec->set_flags( SHF_ALLOC | SHF_WRITE );
     data_sec->set_addr_align( 4 );
-    
+
     char data[] = { '\x48', '\x65', '\x6C', '\x6C', '\x6F',   // msg: db   'Hello, World!', 10
                     '\x2C', '\x20', '\x57', '\x6F', '\x72',
                     '\x6C', '\x64', '\x21', '\x0A'
@@ -63,7 +63,7 @@ bool write_obj_i386( bool is64bit )
     sym_sec->set_link( str_sec->get_index() );
     sym_sec->set_addr_align( 4 );
     sym_sec->set_entry_size( writer.get_default_entry_size( SHT_SYMTAB ) );
-    
+
     symbol_section_accessor symbol_writer( writer, sym_sec );
     Elf_Word nSymIndex = symbol_writer.add_symbol( nStrIndex, 0, 0,
                                                   STB_LOCAL, STT_NOTYPE, 0,
@@ -96,13 +96,13 @@ bool write_obj_i386( bool is64bit )
     section* note_sec = writer.sections.add( ".note" );
     note_sec->set_type( SHT_NOTE );
     note_sec->set_addr_align( 1 );
-    
+
     // Create notes writer
     note_section_accessor note_writer( writer, note_sec );
     note_writer.add_note( 0x77, "Created by ELFIO", 0, 0 );
 
     // Create ELF file
-    writer.save( 
+    writer.save(
         is64bit ?
         "../elf_examples/write_obj_i386_64.o" :
         "../elf_examples/write_obj_i386_32.o"
@@ -150,15 +150,15 @@ bool write_exe_i386( const std::string& filename, bool is64bit, bool set_addr =
     if ( set_addr ) {
         text_sec->set_address( addr );
     }
-    
+
     // Add data into it
-    char text[] = { '\xB8', '\x04', '\x00', '\x00', '\x00',   // mov eax, 4		      
-                    '\xBB', '\x01', '\x00', '\x00', '\x00',   // mov ebx, 1		      
-                    '\xB9', '\x20', '\x80', '\x04', '\x08',   // mov ecx, msg		      
-                    '\xBA', '\x0E', '\x00', '\x00', '\x00',   // mov edx, 14		      
-                    '\xCD', '\x80',                           // int 0x80		      
-                    '\xB8', '\x01', '\x00', '\x00', '\x00',   // mov eax, 1		      
-                    '\xCD', '\x80'                            // int 0x80		      
+    char text[] = { '\xB8', '\x04', '\x00', '\x00', '\x00',   // mov eax, 4
+                    '\xBB', '\x01', '\x00', '\x00', '\x00',   // mov ebx, 1
+                    '\xB9', '\x20', '\x80', '\x04', '\x08',   // mov ecx, msg
+                    '\xBA', '\x0E', '\x00', '\x00', '\x00',   // mov edx, 14
+                    '\xCD', '\x80',                           // int 0x80
+                    '\xB8', '\x01', '\x00', '\x00', '\x00',   // mov eax, 1
+                    '\xCD', '\x80'                            // int 0x80
                   };
     text_sec->set_data( text, sizeof( text ) );
 
@@ -229,7 +229,7 @@ void checkObjestsAreEqual( std::string file_name1, std::string file_name2 )
     BOOST_CHECK_EQUAL( file1.save( file_name2 ), true );
     BOOST_REQUIRE_EQUAL( file1.load( file_name1 ), true );
     BOOST_REQUIRE_EQUAL( file2.load( file_name2 ), true );
-    
+
     for (int i = 0; i < file1.sections.size(); ++i ) {
         BOOST_CHECK_EQUAL( file1.sections[i]->get_address(),
                            file2.sections[i]->get_address() );
@@ -262,7 +262,7 @@ void checkObjestsAreEqual( std::string file_name1, std::string file_name2 )
         BOOST_REQUIRE_NE( file1.sections[i]->get_data(), (const char*)0 );
         BOOST_REQUIRE_NE( file2.sections[i]->get_data(), (const char*)0 );
         std::string pdata1( file1.sections[i]->get_data(),
-                            file1.sections[i]->get_data() +                
+                            file1.sections[i]->get_data() +
                                 file1.sections[i]->get_size() );
         std::string pdata2( file2.sections[i]->get_data(),
                             file2.sections[i]->get_data() +
@@ -282,7 +282,7 @@ void checkObjestsAreEqual( std::string file_name1, std::string file_name2 )
 void checkExeAreEqual( std::string file_name1, std::string file_name2, int skipTests = 0 )
 {
     checkObjestsAreEqual( file_name1, file_name2 );
-    
+
     elfio file1;
     elfio file2;
 
@@ -357,7 +357,7 @@ BOOST_AUTO_TEST_CASE( section_header_address_update )
     BOOST_REQUIRE_NE( sec, (section*)0 );
     BOOST_CHECK_EQUAL( sec->get_address(), 0x08048100 );
 
-    
+
     const std::string file_wo_addr ( "../elf_examples/write_exe_i386_32_wo_addr" );
     write_exe_i386( file_wo_addr, false, false, 0 );
     reader.load( file_wo_addr );
@@ -377,7 +377,7 @@ BOOST_AUTO_TEST_CASE( elfio_copy )
 
     e.load( filename );
     Elf_Half num     = e.sections.size();
-    //section* new_sec = 
+    //section* new_sec =
         e.sections.add( "new" );
     e.save( filename );
     BOOST_CHECK_EQUAL( num + 1, e.sections.size() );
@@ -452,7 +452,7 @@ BOOST_AUTO_TEST_CASE( get_symbol_32 )
     section* psymsec = elf.sections[ ".symtab" ];
     const symbol_section_accessor symbols( elf, psymsec );
 
-    BOOST_CHECK_EQUAL( true, 
+    BOOST_CHECK_EQUAL( true,
         symbols.get_symbol( 0x08048478, name, size, bind,
                                         type, section_index, other) );
     BOOST_CHECK_EQUAL( "_IO_stdin_used", name );
@@ -476,10 +476,79 @@ BOOST_AUTO_TEST_CASE( get_symbol_64 )
     section* psymsec = elf.sections[ ".symtab" ];
     const symbol_section_accessor symbols( elf, psymsec );
 
-    BOOST_CHECK_EQUAL( true, 
+    BOOST_CHECK_EQUAL( true,
         symbols.get_symbol(0x00400498, name, size, bind,
                                        type, section_index, other) );
     BOOST_CHECK_EQUAL( "main", name );
     BOOST_CHECK_EQUAL( 12, section_index );
     BOOST_CHECK_EQUAL( 21, size );
 }
+
+////////////////////////////////////////////////////////////////////////////////
+BOOST_AUTO_TEST_CASE( null_section_inside_segment )
+{
+    // This test case checks the load/save of SHT_NULL sections in a segment
+    // See https://github.com/serge1/ELFIO/issues/19
+    //
+    // Note: The test case checking the load/save of a segment containing no section
+    // is covered by elf_object_copy_32: ../elf_examples/hello_32 has empty segments
+
+    // Create an ELF file with SHT_NULL sections at the beginning/middle/end of a segment
+    elfio writer;
+    writer.create( ELFCLASS32, ELFDATA2LSB );
+    writer.set_os_abi( ELFOSABI_LINUX );
+    writer.set_type( ET_EXEC );
+    writer.set_machine( EM_386 );
+    // Create code section 1
+    section* text_sec1 = writer.sections.add( ".text1" );
+    text_sec1->set_type( SHT_PROGBITS );
+    text_sec1->set_flags( SHF_ALLOC | SHF_EXECINSTR );
+    text_sec1->set_addr_align( 0x10 );
+    text_sec1->set_address( 0x08048000 );
+    char text[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+    text_sec1->set_data( text, sizeof( text ) );
+    // Create code section 2
+    section* text_sec2 = writer.sections.add( ".text2" );
+    text_sec2->set_type( SHT_PROGBITS );
+    text_sec2->set_flags( SHF_ALLOC | SHF_EXECINSTR );
+    text_sec2->set_addr_align( 0x10 );
+    text_sec2->set_address( 0x08048010 );
+    text_sec2->set_data( text, sizeof( text ) );
+    // Create null sections
+    section* null_sec1 = writer.sections.add( "null" );
+    null_sec1->set_type( SHT_NULL );
+    null_sec1->set_flags( SHF_ALLOC | SHF_EXECINSTR );
+    null_sec1->set_address( 0x08048000 );
+    section* null_sec2 = writer.sections.add( "null" );
+    null_sec2->set_type( SHT_NULL );
+    null_sec2->set_flags( SHF_ALLOC | SHF_EXECINSTR );
+    null_sec2->set_address( 0x08048010 );
+    section* null_sec3 = writer.sections.add( "null" );
+    null_sec3->set_type( SHT_NULL );
+    null_sec3->set_flags( SHF_ALLOC | SHF_EXECINSTR );
+    null_sec3->set_address( 0x08048020 );
+    // Create a loadable segment
+    segment* text_seg = writer.segments.add();
+    text_seg->set_type( PT_LOAD );
+    text_seg->set_virtual_address( 0x08048000 );
+    text_seg->set_physical_address( 0x08048000 );
+    text_seg->set_flags( PF_X | PF_R );
+    text_seg->set_align( 0x1000 );
+    // Add sections into the loadable segment
+    text_seg->add_section_index( null_sec1->get_index(), null_sec1->get_addr_align() );
+    text_seg->add_section_index( text_sec1->get_index(), text_sec1->get_addr_align() );
+    text_seg->add_section_index( null_sec2->get_index(), null_sec2->get_addr_align() );
+    text_seg->add_section_index( text_sec2->get_index(), text_sec2->get_addr_align() );
+    text_seg->add_section_index( null_sec3->get_index(), null_sec3->get_addr_align() );
+    // Setup entry point
+    writer.set_entry( 0x08048000 );
+    // Create ELF file
+    std::string f1 = "../elf_examples/null_section_inside_segment1";
+    std::string f2 = "../elf_examples/null_section_inside_segment2";
+    BOOST_CHECK_EQUAL( writer.save(f1), true );
+
+    // Load and check the ELF file created above
+    elfio elf;
+    BOOST_CHECK_EQUAL( elf.load(f1), true );
+    BOOST_CHECK_EQUAL( elf.save(f2), true );
+}
diff --git a/elfio/elfio.hpp b/elfio/elfio.hpp
index 0ab8552..c92ba62 100644
--- a/elfio/elfio.hpp
+++ b/elfio/elfio.hpp
@@ -666,9 +666,7 @@ class elfio
                     header->get_segment_entry_size() * header->get_segments_num();
             }
             // Special case:
-            // Segments which start with the NULL section and have further sections
-            else if ( seg->get_sections_num() > 1
-                      && sections[seg->get_section_index_at( 0 )]->get_type() == SHT_NULL ) {
+            else if ( seg->is_offset_initialized() && seg->get_offset() == 0 ) {
                 seg_start_pos = 0;
                 if ( seg->get_sections_num() ) {
                     segment_memory = segment_filesize = current_file_pos;
-- 
GitLab