elf: enforce minimum symbol/relocation entry size (P1 #25)

ober

7f4284a4af6c4fca334fbf6a976d23c0b8eb278e

diff --git a/lib/jasm/object/elf.ss b/lib/jasm/object/elf.ss
index cc4a257..5886412 100644
--- a/lib/jasm/object/elf.ss
+++ b/lib/jasm/object/elf.ss
@@ -372,47 +372,50 @@
             (list name-offset info other section-index value size))))
 
     (define (parse-symbols-for-section class endian bv sections table-section)
-      (let* ([entry-size (if (zero? (elf-section-entry-size table-section))
-                             (if (eq? class 'elf64) 24 16)
-                             (elf-section-entry-size table-section))]
-             [count (div (elf-section-size table-section) entry-size)]
-             [string-section (list-ref/default sections (elf-section-link table-section) #f)]
-             [string-bounds (if string-section
-                                (cons (elf-section-offset string-section)
-                                      (+ (elf-section-offset string-section)
-                                         (elf-section-size string-section)))
-                                (cons 0 0))])
-        (let loop ([index 0] [symbols '()])
-          (if (= index count)
-              (reverse symbols)
-              (let* ([entry-offset (+ (elf-section-offset table-section)
-                                      (* index entry-size))]
-                     [entry (parse-symbol-entry class endian bv entry-offset)]
-                     [name-offset (list-ref entry 0)]
-                     [info (list-ref entry 1)]
-                     [other (list-ref entry 2)]
-                     [section-index (list-ref entry 3)]
-                     [value (list-ref entry 4)]
-                     [size (list-ref entry 5)]
-                     [binding (symbol-binding-name (div info 16))]
-                     [type (symbol-type-name (mod info 16))]
-                     [visibility (symbol-visibility-name (bitwise-and other #x3))]
-                     [name (if (or (zero? name-offset) (not string-section))
-                               ""
-                               (read-c-string bv
-                                              (+ (car string-bounds) name-offset)
-                                              (cdr string-bounds)))])
-                (loop (+ index 1)
-                      (cons (make-elf-symbol index
-                                             name
-                                             value
-                                             size
-                                             binding
-                                             type
-                                             visibility
-                                             section-index
-                                             (elf-section-name table-section))
-                            symbols)))))))
+      (let* ([minimum (if (eq? class 'elf64) 24 16)]
+             [entry-size (if (zero? (elf-section-entry-size table-section))
+                             minimum
+                             (elf-section-entry-size table-section))])
+        (when (< entry-size minimum)
+          (error 'read-elf-bytevector "ELF symbol entry size is too small" entry-size))
+        (let* ([count (div (elf-section-size table-section) entry-size)]
+               [string-section (list-ref/default sections (elf-section-link table-section) #f)]
+               [string-bounds (if string-section
+                                  (cons (elf-section-offset string-section)
+                                        (+ (elf-section-offset string-section)
+                                           (elf-section-size string-section)))
+                                  (cons 0 0))])
+          (let loop ([index 0] [symbols '()])
+            (if (= index count)
+                (reverse symbols)
+                (let* ([entry-offset (+ (elf-section-offset table-section)
+                                        (* index entry-size))]
+                       [entry (parse-symbol-entry class endian bv entry-offset)]
+                       [name-offset (list-ref entry 0)]
+                       [info (list-ref entry 1)]
+                       [other (list-ref entry 2)]
+                       [section-index (list-ref entry 3)]
+                       [value (list-ref entry 4)]
+                       [size (list-ref entry 5)]
+                       [binding (symbol-binding-name (div info 16))]
+                       [type (symbol-type-name (mod info 16))]
+                       [visibility (symbol-visibility-name (bitwise-and other #x3))]
+                       [name (if (or (zero? name-offset) (not string-section))
+                                 ""
+                                 (read-c-string bv
+                                                (+ (car string-bounds) name-offset)
+                                                (cdr string-bounds)))])
+                  (loop (+ index 1)
+                        (cons (make-elf-symbol index
+                                               name
+                                               value
+                                               size
+                                               binding
+                                               type
+                                               visibility
+                                               section-index
+                                               (elf-section-name table-section))
+                              symbols))))))))
 
     (define (parse-symbols class endian bv sections)
       (let ([all-sections sections])
@@ -446,34 +449,37 @@
 
     (define (parse-relocations-for-section class endian bv table-section)
       (let* ([rela? (= (elf-section-type table-section) 4)]
+             [minimum (cond
+                        [(and (eq? class 'elf64) rela?) 24]
+                        [(eq? class 'elf64) 16]
+                        [rela? 12]
+                        [else 8])]
              [entry-size (if (zero? (elf-section-entry-size table-section))
-                             (cond
-                               [(and (eq? class 'elf64) rela?) 24]
-                               [(eq? class 'elf64) 16]
-                               [rela? 12]
-                               [else 8])
-                             (elf-section-entry-size table-section))]
-             [count (div (elf-section-size table-section) entry-size)]
-             [target-section-index (elf-section-info table-section)])
-        (let loop ([index 0] [relocations '()])
-          (if (= index count)
-              (reverse relocations)
-              (let* ([entry-offset (+ (elf-section-offset table-section)
-                                      (* index entry-size))]
-                     [entry (parse-relocation-entry class endian bv entry-offset rela?)]
-                     [offset (list-ref entry 0)]
-                     [symbol-index (list-ref entry 1)]
-                     [type (list-ref entry 2)]
-                     [addend (list-ref entry 3)])
-                (loop (+ index 1)
-                      (cons (make-elf-relocation index
-                                                 (elf-section-name table-section)
-                                                 target-section-index
-                                                 offset
-                                                 symbol-index
-                                                 type
-                                                 addend)
-                            relocations)))))))
+                             minimum
+                             (elf-section-entry-size table-section))])
+        (when (< entry-size minimum)
+          (error 'read-elf-bytevector "ELF relocation entry size is too small" entry-size))
+        (let* ([count (div (elf-section-size table-section) entry-size)]
+               [target-section-index (elf-section-info table-section)])
+          (let loop ([index 0] [relocations '()])
+            (if (= index count)
+                (reverse relocations)
+                (let* ([entry-offset (+ (elf-section-offset table-section)
+                                        (* index entry-size))]
+                       [entry (parse-relocation-entry class endian bv entry-offset rela?)]
+                       [offset (list-ref entry 0)]
+                       [symbol-index (list-ref entry 1)]
+                       [type (list-ref entry 2)]
+                       [addend (list-ref entry 3)])
+                  (loop (+ index 1)
+                        (cons (make-elf-relocation index
+                                                   (elf-section-name table-section)
+                                                   target-section-index
+                                                   offset
+                                                   symbol-index
+                                                   type
+                                                   addend)
+                              relocations))))))))
 
     (define (parse-relocations class endian bv sections)
       (let loop ([sections sections] [relocations '()])
diff --git a/tests/test-jasm.ss b/tests/test-jasm.ss
index 6e38b6d..edd6088 100644
--- a/tests/test-jasm.ss
+++ b/tests/test-jasm.ss
@@ -307,6 +307,12 @@
           (elf-relocation-addend relocation)))
   '(1 #t ".rela.text" 1 4097 1 4 -4))
 
+(test "elf minimum entry size parses"
+  (let ([obj (read-elf-bytevector (sample-elf64le))])
+    (list (length (elf-object-symbols obj))
+          (length (elf-object-relocations obj))))
+  '(2 1))
+
 (test "elf file reader"
   (let ([path ".jasm-test-sample.o"])
     (write-test-bytevector-file path (sample-elf64le))
diff --git a/tests/test-malformed-objects.ss b/tests/test-malformed-objects.ss
index 5c071bd..45e9709 100644
--- a/tests/test-malformed-objects.ss
+++ b/tests/test-malformed-objects.ss
@@ -101,6 +101,24 @@
     (put16le! bv 60 1)
     bv))
 
+(def (elf-with-small-table-entry section-type)
+  (let ([bv (make-bytevector 512 0)])
+    (put8! bv 0 #x7f)
+    (put-ascii! bv 1 "ELF")
+    (put8! bv 4 2)
+    (put8! bv 5 1)
+    (put8! bv 6 1)
+    (put32le! bv 20 1)
+    (put32le! bv 40 64)
+    (put16le! bv 58 64)
+    (put16le! bv 60 2)
+    (put16le! bv 62 0)
+    (put32le! bv 132 section-type)
+    (put32le! bv 152 256)
+    (put32le! bv 160 48)
+    (put32le! bv 184 1)
+    bv))
+
 (def (coff-with-truncated-section-table)
   (let ([bv (make-bytevector 20 0)])
     (put16le! bv 0 #x8664)
@@ -130,6 +148,12 @@
 (test-raises "elf section entry size too small"
   (read-elf-bytevector (elf-with-small-section-entry)))
 
+(test-raises "elf symtab entry size too small"
+  (read-elf-bytevector (elf-with-small-table-entry 2)))
+
+(test-raises "elf rela entry size too small"
+  (read-elf-bytevector (elf-with-small-table-entry 4)))
+
 (test-raises "mach-o zero command size"
   (read-macho-bytevector (macho-with-zero-command-size)))