macho: bound ncmds by sizeofcmds and validate nsyms upfront

ober

406c270ccbadad626e0b76f84adf9038e4b2e5ee

diff --git a/lib/jasm/object/macho.ss b/lib/jasm/object/macho.ss
index 0cd6bc3..c9fcd13 100644
--- a/lib/jasm/object/macho.ss
+++ b/lib/jasm/object/macho.ss
@@ -240,6 +240,8 @@
                  [stroff (list-ref symtab 2)]
                  [strsize (list-ref symtab 3)]
                  [str-limit (+ stroff strsize)])
+            (when (> (+ symoff (* nsyms 16)) (bv-len bv))
+              (error 'read-macho-bytevector "Mach-O symtab count exceeds file" nsyms))
             (let loop ([index 0] [symbols '()])
               (if (= index nsyms)
                   (reverse symbols)
@@ -271,6 +273,8 @@
                [sizeofcmds (u32 bv 20 endian)]
                [command-info #f])
           (require-range 'read-macho-bytevector bv 32 sizeofcmds)
+          (when (> ncmds (div sizeofcmds 8))
+            (error 'read-macho-bytevector "Mach-O load command count exceeds command size" ncmds sizeofcmds))
           (set! command-info (parse-load-commands endian bv ncmds))
           (make-macho-object endian
                              cpu-type
diff --git a/tests/test-malformed-objects.ss b/tests/test-malformed-objects.ss
index 45e9709..1540766 100644
--- a/tests/test-malformed-objects.ss
+++ b/tests/test-malformed-objects.ss
@@ -68,6 +68,34 @@
     (put32le! bv #x60 1)
     bv))
 
+(def (macho-ncmds-exceeds-sizeofcmds)
+  (let ([bv (make-bytevector 48 0)])
+    (put32le! bv 0 #xfeedfacf)
+    (put32le! bv 4 #x0100000c)
+    (put32le! bv 12 1)
+    (put32le! bv 16 2)
+    (put32le! bv 20 8)
+    (put32le! bv 32 #xff)
+    (put32le! bv 36 8)
+    (put32le! bv 40 #xff)
+    (put32le! bv 44 8)
+    bv))
+
+(def (macho-symtab-count-overrun)
+  (let ([bv (make-bytevector 56 0)])
+    (put32le! bv 0 #xfeedfacf)
+    (put32le! bv 4 #x0100000c)
+    (put32le! bv 12 1)
+    (put32le! bv 16 1)
+    (put32le! bv 20 24)
+    (put32le! bv 32 #x2)
+    (put32le! bv 36 24)
+    (put32le! bv 40 0)
+    (put32le! bv 44 #x10000000)
+    (put32le! bv 48 0)
+    (put32le! bv 52 0)
+    bv))
+
 (def (archive-invalid-bsd-long-name)
   (let ([bv (make-bytevector 72 (char->integer #\space))])
     (put-ascii! bv 0 "!<arch>\n")
@@ -160,6 +188,12 @@
 (test-raises "mach-o segment section overrun"
   (read-macho-bytevector (macho-segment-with-section-overrun)))
 
+(test-raises "mach-o ncmds exceeds sizeofcmds"
+  (read-macho-bytevector (macho-ncmds-exceeds-sizeofcmds)))
+
+(test-raises "mach-o symtab count overrun"
+  (read-macho-bytevector (macho-symtab-count-overrun)))
+
 (test-raises "coff truncated section table"
   (read-coff-bytevector (coff-with-truncated-section-table)))