elf: enforce minimum symbol/relocation entry size (P1 #25)
ober
7f4284a4af6c4fca334fbf6a976d23c0b8eb278e
--- 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 '()]) --- 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)) --- 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)))