Add some bounds checking to ELF file parsing
diff --git a/elf/elf_file.cpp b/elf/elf_file.cpp
index d4f8d53..d8f5087 100644
--- a/elf/elf_file.cpp
+++ b/elf/elf_file.cpp
@@ -188,8 +188,12 @@
     return ERROR_INCOMPATIBLE;
 }
 
+bool elf_file::in_bounds(uint32_t offset, uint32_t length) const {
+    return offset <= elf_bytes.size() && length <= elf_bytes.size() - offset;
+}
+
 void elf_file::read_bytes(unsigned offset, unsigned length, void *dest) {
-    if (offset + length > elf_bytes.size()) {
+    if (!in_bounds(offset, length)) {
         fail(ERROR_FORMAT, "ELF File Read from 0x%x with size 0x%x exceeds the file size 0x%zx", offset, length, elf_bytes.size());
     }
     memcpy(dest, &elf_bytes[offset], length);
@@ -356,11 +360,13 @@
     if (!eh.sh_str_index || eh.sh_str_index > eh.sh_num || eh.sh_str_index >= sh_data.size())
         return "";
 
-    if (sh_name > sh_data[eh.sh_str_index].size())
+    const auto &strings = sh_data[eh.sh_str_index];
+    if (sh_name >= strings.size())
         return "";
 
-    const char * str =(const char *) &sh_data[eh.sh_str_index][0];
-    return &str[sh_name];
+    // Don't assume the string table is null terminated
+    const char * str = (const char *) &strings[sh_name];
+    return std::string(str, strnlen(str, strings.size() - sh_name));
 }
 
 const elf32_sh_entry* elf_file::get_section(const std::string &sh_name) {
@@ -381,11 +387,14 @@
     auto data = content(*sym_tab);
     auto strings = content(*str_tab);
     const char * str =(const char *) strings.data();
-    for (unsigned int i=0; i < sym_tab->size / sizeof(elf32_sym_entry); i++) {
+    for (unsigned int i=0; i < data.size() / sizeof(elf32_sym_entry); i++) {
         elf32_sym_entry sym;
         memcpy(&sym, data.data() + i*sizeof(elf32_sym_entry), sizeof(elf32_sym_entry));
         sym_he(sym);    // swap to Host for processing
-        if (&str[sym.name] == sym_name) {
+        if (sym.name >= strings.size()) {
+            continue;
+        }
+        if (std::string(&str[sym.name], strnlen(&str[sym.name], strings.size() - sym.name)) == sym_name) {
             return sym.value;
         }
     }
@@ -491,12 +500,21 @@
 
 std::vector<uint8_t> elf_file::content(const elf32_ph_entry &ph) const {
     std::vector<uint8_t> content;
+    if (!in_bounds(ph.offset, ph.filez)) {
+        fail(ERROR_FORMAT, "ELF segment at offset 0x%x with size 0x%x exceeds the file size 0x%zx", ph.offset, ph.filez, elf_bytes.size());
+    }
     std::copy(elf_bytes.begin() + ph.offset, elf_bytes.begin() + ph.offset + ph.filez, std::back_inserter(content));
     return content;
 }
 
 std::vector<uint8_t> elf_file::content(const elf32_sh_entry &sh) const {
     std::vector<uint8_t> content;
+    if (sh.type == SHT_NOBITS) {
+        return content; // occupies no space in the file
+    }
+    if (!in_bounds(sh.offset, sh.size)) {
+        fail(ERROR_FORMAT, "ELF section at offset 0x%x with size 0x%x exceeds the file size 0x%zx", sh.offset, sh.size, elf_bytes.size());
+    }
     std::copy(elf_bytes.begin() + sh.offset, elf_bytes.begin() + sh.offset + sh.size, std::back_inserter(content));
     return content;
 }
@@ -504,6 +522,9 @@
 void elf_file::content(const elf32_ph_entry &ph, const std::vector<uint8_t> &content) {
     if (!editable) return;
     assert(content.size() <= ph.filez);
+    if (!in_bounds(ph.offset, ph.filez)) {
+        fail(ERROR_FORMAT, "ELF segment at offset 0x%x with size 0x%x exceeds the file size 0x%zx", ph.offset, ph.filez, elf_bytes.size());
+    }
     if (verbose) printf("Update segment content offset %x content size %zx physical size %x\n", ph.offset, content.size(), ph.filez);
     memcpy(&elf_bytes[ph.offset], &content[0], std::min(content.size(), (size_t) ph.filez));
     read_sh_data(); // Extract the sections after modifying the content
@@ -512,6 +533,9 @@
 void elf_file::content(const elf32_sh_entry &sh, const std::vector<uint8_t> &content) {
     if (!editable) return;
     assert(content.size() <= sh.size);
+    if (sh.type == SHT_NOBITS || !in_bounds(sh.offset, sh.size)) {
+        fail(ERROR_FORMAT, "ELF section at offset 0x%x with size 0x%x cannot be written", sh.offset, sh.size);
+    }
     if (verbose) printf("Update section content offset %x content size %zx section size %x\n", sh.offset, content.size(), sh.size);
     memcpy(&elf_bytes[sh.offset], &content[0], std::min(content.size(), (size_t) sh.size));
     read_sh_data();  // Extract the sections after modifying the content
diff --git a/elf/elf_file.h b/elf/elf_file.h
index 96c147d..f6f1f6b 100644
--- a/elf/elf_file.h
+++ b/elf/elf_file.h
@@ -64,6 +64,7 @@
     void read_ph(void);
     void read_sh(void);
     void read_sh_data(void);
+    bool in_bounds(uint32_t offset, uint32_t length) const;
     void read_bytes(unsigned offset, unsigned length, void *dest);
     uint32_t append_section_name(const std::string &sh_name_str);
     void flatten(void);