From 07ef3175506ede90996023002cf834b12c2341bc Mon Sep 17 00:00:00 2001
From: Serge Lamikhov-Center <to_serge@hotmail.com>
Date: Thu, 16 Jun 2022 17:30:22 +0300
Subject: [PATCH] Check out of the file boundary access attemps

---
 .vscode/launch.json     | 14 +++++++++++---
 elfio/elfio.hpp         |  4 ++--
 elfio/elfio_section.hpp | 11 +++++++++--
 elfio/elfio_segment.hpp | 11 +++++++++--
 tests/elfio_fuzzer.cpp  | 16 ++++++++++++++++
 5 files changed, 47 insertions(+), 9 deletions(-)
 create mode 100644 tests/elfio_fuzzer.cpp

diff --git a/.vscode/launch.json b/.vscode/launch.json
index 9e8f8c7..eb33f0c 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -34,7 +34,7 @@
             "request": "launch",
             "program": "${workspaceFolder}/build/examples/elfdump/elfdump",
             "args": [
-                "tests/elf_examples/hello_32"
+                "tests/slow-unit-98e0b3724bca5039b0c12d9e31f6afcbe4f3ce64"
             ],
             "stopAtEntry": false,
             "cwd": "${workspaceFolder}",
@@ -60,7 +60,6 @@
                 "11706",
                 "/usr/bin/bash"
             ],
-            "sudo": true,
             "stopAtEntry": false,
             "cwd": "${workspaceFolder}",
             "environment": [],
@@ -83,7 +82,6 @@
             "args": [
                 "/proc/kcore"
             ],
-            "sudo": true,
             "stopAtEntry": false,
             "cwd": "${workspaceFolder}",
             "environment": [],
@@ -97,6 +95,16 @@
                 }
             ],
             "miDebuggerPath": "/home/user/ELFIO/examples/sudo_gdb.sh"
+        },
+        {
+            "name": "Fuzzer",
+            "type": "lldb",
+            "request": "launch",
+            "program": "${workspaceFolder}/tests/elfio_fuzzer",
+            "args": [
+                "crash-da39a3ee5e6b4b0d3255bfef95601890afd80709"
+            ],
+            "cwd": "${workspaceFolder}/tests",
         }
     ]
 }
\ No newline at end of file
diff --git a/elfio/elfio.hpp b/elfio/elfio.hpp
index c6a4f25..c5b879f 100644
--- a/elfio/elfio.hpp
+++ b/elfio/elfio.hpp
@@ -172,8 +172,8 @@ class elfio
             return false;
         }
 
-        load_sections( stream );
-        bool is_still_good = load_segments( stream );
+        bool is_still_good = load_sections( stream );
+        is_still_good      = is_still_good && load_segments( stream );
         return is_still_good;
     }
 
diff --git a/elfio/elfio_section.hpp b/elfio/elfio_section.hpp
index a71559a..5874859 100644
--- a/elfio/elfio_section.hpp
+++ b/elfio/elfio_section.hpp
@@ -62,7 +62,7 @@ class section
     ELFIO_SET_ACCESS_DECL( Elf64_Off, offset );
     ELFIO_SET_ACCESS_DECL( Elf_Half, index );
 
-    virtual void load( std::istream& stream, std::streampos header_offset ) = 0;
+    virtual bool load( std::istream& stream, std::streampos header_offset ) = 0;
     virtual void save( std::ostream&  stream,
                        std::streampos header_offset,
                        std::streampos data_offset )                         = 0;
@@ -201,7 +201,7 @@ template <class T> class section_impl : public section
     void set_index( Elf_Half value ) override { index = value; }
 
     //------------------------------------------------------------------------------
-    void load( std::istream& stream, std::streampos header_offset ) override
+    bool load( std::istream& stream, std::streampos header_offset ) override
     {
         std::fill_n( reinterpret_cast<char*>( &header ), sizeof( header ),
                      '\0' );
@@ -226,6 +226,11 @@ template <class T> class section_impl : public section
                 stream.seekg(
                     ( *translator )[( *convertor )( header.sh_offset )] );
                 stream.read( data, size );
+                if (stream.gcount() != size) {
+                    delete[] data;
+                    data = nullptr;
+                    return false;
+                }
                 data[size] = 0; // Ensure data is ended with 0 to avoid oob read
                 data_size  = decltype( data_size )( size );
             }
@@ -233,6 +238,8 @@ template <class T> class section_impl : public section
                 data_size = 0;
             }
         }
+
+        return true;
     }
 
     //------------------------------------------------------------------------------
diff --git a/elfio/elfio_segment.hpp b/elfio/elfio_segment.hpp
index bc6114f..b8b9809 100644
--- a/elfio/elfio_segment.hpp
+++ b/elfio/elfio_segment.hpp
@@ -61,7 +61,7 @@ class segment
     ELFIO_SET_ACCESS_DECL( Elf_Half, index );
 
     virtual const std::vector<Elf_Half>& get_sections() const               = 0;
-    virtual void load( std::istream& stream, std::streampos header_offset ) = 0;
+    virtual bool load( std::istream& stream, std::streampos header_offset ) = 0;
     virtual void save( std::ostream&  stream,
                        std::streampos header_offset,
                        std::streampos data_offset )                         = 0;
@@ -159,7 +159,7 @@ template <class T> class segment_impl : public segment
     void set_index( Elf_Half value ) override { index = value; }
 
     //------------------------------------------------------------------------------
-    void load( std::istream& stream, std::streampos header_offset ) override
+    bool load( std::istream& stream, std::streampos header_offset ) override
     {
         if ( translator->empty() ) {
             stream.seekg( 0, stream.end );
@@ -185,10 +185,17 @@ template <class T> class segment_impl : public segment
 
                 if ( nullptr != data ) {
                     stream.read( data, size );
+                    if (stream.gcount() != size) {
+                        delete[] data;
+                        data = nullptr;
+                        return false;
+                    }
                     data[size] = 0;
                 }
             }
         }
+
+        return true;
     }
 
     //------------------------------------------------------------------------------
diff --git a/tests/elfio_fuzzer.cpp b/tests/elfio_fuzzer.cpp
new file mode 100644
index 0000000..8154a11
--- /dev/null
+++ b/tests/elfio_fuzzer.cpp
@@ -0,0 +1,16 @@
+#include <string>
+#include <sstream>
+
+#include <elfio/elfio.hpp>
+using namespace ELFIO;
+
+extern "C" int LLVMFuzzerTestOneInput( const uint8_t* Data, size_t Size )
+{
+    std::string        str( (const char*)Data, Size );
+    std::istringstream ss( str );
+
+    elfio elf;
+    elf.load( ss );
+
+    return 0;
+}
-- 
GitLab