Skip to content

Commit ca0afd4

Browse files
committed
Fixes from fuzzing testing
This slows down simple-array fixnum reading on sbcl because we need to protect against malicious data. It's still very very fast. If you need faster we can SIMD a check or something.
1 parent 3cbd661 commit ca0afd4

14 files changed

+126
-49
lines changed

benchmarks.lisp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
(with-open-file (str "blarg.bin" :if-exists :supersede :if-does-not-exist :create
6262
:direction :output :element-type '(unsigned-byte 8))
6363
(cl-binary-store:store str data))))))
64+
;;(assert (equalp (cl-binary-store:restore store) data))
6465
(when read
6566
(timed (" READ :" repeats output-size-MB)
6667
(dotimes (x repeats) (cl-binary-store:restore store)))

src/array.lisp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,35 @@
11
(in-package :cl-binary-store)
22

33
(defun restore-array (storage restore-object)
4-
(declare (type function restore-object))
4+
(declare (type function restore-object) (optimize (speed 3) (safety 1)))
55
(let* ((has-fill-pointer (funcall restore-object))
66
(fill-pointer (when has-fill-pointer (restore-tagged-unsigned-fixnum storage)))
77
(adjustable (funcall restore-object))
88
(array-rank (the (unsigned-byte 8) (restore-ub8 storage)))
99
(dimensions (loop repeat array-rank
1010
collect (restore-tagged-unsigned-fixnum storage)))
11-
(displaced (funcall restore-object)))
12-
(check-if-too-much-data (read-storage-max-to-read storage) (reduce #'* dimensions))
11+
(displaced (funcall restore-object))
12+
(array-total-size (reduce #'* dimensions)))
13+
(unless (and (typep array-total-size 'fixnum) (>= array-total-size 0))
14+
(unexpected-data "Array total size is too large"))
15+
(check-if-too-much-data (read-storage-max-to-read storage) array-total-size)
1316
(labels ((check-fill-pointer (dimensions)
1417
(when has-fill-pointer
1518
(unless (= array-rank 1)
1619
(unexpected-data "found fill-pointer for a non-vector"))
17-
(unless (<= fill-pointer (length (first dimensions)))
18-
(unexpected-data (format nil "fill-pointer ~A > dimensions ~A"
19-
fill-pointer dimensions))))))
20+
(unless (<= fill-pointer (first dimensions))
21+
(unexpected-data "fill-pointer > vector length")))
22+
(values)))
2023
(if displaced
2124
(let ((element-type (funcall restore-object))
2225
(offset (restore-tagged-unsigned-fixnum storage))
2326
(displaced-to (funcall restore-object)))
2427
(unless (typep displaced-to 'array)
25-
(unexpected-data "array" displaced-to))
28+
(unexpected-data "displaced to a non array?!"))
2629
(unless (typep (array-element-type displaced-to) element-type)
27-
(unexpected-data (format nil "array with element-type ~A" element-type)
28-
displaced-to))
30+
(unexpected-data "array displaced to array of different element-type"))
2931
(unless (< offset (array-total-size displaced-to))
30-
(unexpected-data (format nil "array of total size > ~A" offset)
31-
displaced-to))
32+
(unexpected-data "array displaced to too small array"))
3233
(when has-fill-pointer (check-fill-pointer dimensions))
3334
(make-array dimensions :element-type element-type :adjustable adjustable
3435
:fill-pointer fill-pointer :displaced-to displaced-to
@@ -42,7 +43,7 @@
4243
;; We need to make our array first in case any of the array elements refer to it!
4344
;; If we are ever referred to, then there will already be a fixup in place for
4445
;; our array handled by `restore-new-reference-indicator'.
45-
(loop for idx fixnum from 0 below (array-total-size array)
46+
(loop for idx fixnum from 0 below array-total-size
4647
do (restore-object-to (row-major-aref array idx) restore-object))
4748
array))))))
4849

src/basic-codespace.lisp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"This is the basic codespace of cl-binary-store.")
1818

1919
;; Enable debug to get source code saved to a file so the debugger does the right thing
20-
(define-codespace ("basic codespace" +basic-codespace+ :debug nil)
20+
(define-codespace ("basic codespace" +basic-codespace+ :debug t)
2121
(register-references num-eq-refs (make-hash-table :test #'eq :size *num-eq-refs-table-size*))
2222
(register-references
2323
double-float-refs (make-hash-table :test #+sbcl #'double-float-= #-sbcl #'eql

src/cl-binary-store.lisp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,14 @@
214214
())
215215

216216
(defun unexpected-data (expected &optional (data nil data-provided-p))
217-
(error 'invalid-input-data :format-control "Expected ~A~A" :format-arguments (list expected (if data-provided-p (format nil ", found ~A" data) ""))))
217+
(error 'invalid-input-data
218+
:format-control "Expected ~A~A"
219+
:format-arguments (list expected
220+
(if data-provided-p
221+
;; be careful not to provide anything
222+
;; that cannot be printed trivially here!
223+
(format nil ", found ~A" data)
224+
""))))
218225

219226
(define-condition maybe-expected-error (invalid-input-data)
220227
()

src/hash-table.lisp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
#-sbcl (declare (ignore synchronized weakness))
3232
;; weakness works as far as I can discern
3333
;; because of how we do reference restoration
34+
(unless (typep rehash-size '(or (integer 1 *) (float (1.0) *)))
35+
(unexpected-data "rehash-size is not correct"))
36+
(unless (< size (ash most-positive-fixnum -4))
37+
(unexpected-data "hash table too large"))
3438
(check-if-too-much-data (read-storage-max-to-read storage)
3539
(* 16 size)) ;; an estimate
3640
(make-hash-table :test test :size size

src/numbers.lisp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@
104104
(let* ((offset (read-storage-offset storage))
105105
(fixnum (signed-sap-ref-64 (read-storage-sap storage) offset)))
106106
(unless (typep fixnum 'fixnum)
107-
(unexpected-data "fixnum" fixnum))
107+
(unexpected-data "expected fixnum" fixnum))
108108
(setf (read-storage-offset storage) (truly-the fixnum (+ offset 8)))
109109
(truly-the fixnum fixnum)))
110110

@@ -232,17 +232,17 @@
232232

233233
(declaim (inline ensure-integer))
234234
(defun ensure-integer (x)
235-
(unless (integerp x)
236-
(unexpected-data "integer" x))
237-
x)
235+
(if (integerp x)
236+
x
237+
(progn (unexpected-data "expected an integer") 0)))
238238

239239
(defun restore-ratio (restore-object)
240240
(declare (optimize (speed 3) (safety 1)) (type function restore-object))
241241
(let ((a (ensure-integer (funcall restore-object)))
242242
(b (ensure-integer (funcall restore-object))))
243243
(declare (type integer a b))
244-
(unless (> b 0)
245-
(unexpected-data "integer > 0" b))
244+
(when (= b 0)
245+
(unexpected-data "ratio denominator is 0"))
246246
(/ (the integer a) (the integer b))))
247247

248248
(defun store-ratio (ratio storage num-eq-refs assign-new-reference-id)
@@ -261,9 +261,9 @@
261261

262262
(declaim (inline ensure-real))
263263
(defun ensure-real (x)
264-
(unless (typep x 'real)
265-
(unexpected-data "real" x))
266-
x)
264+
(if (typep x 'real)
265+
x
266+
(progn (unexpected-data "real") 0)))
267267

268268
(defun restore-complex (restore-object)
269269
(declare (type function restore-object))
@@ -328,8 +328,8 @@
328328
(#.+ub32-code+ (restore-ub32 storage))
329329
(#.+fixnum-code+
330330
(let ((fixnum (restore-fixnum storage)))
331-
(unless (>= fixnum 0)
332-
(unexpected-data "unsigned fixnum" fixnum))
331+
(unless (<= 0 fixnum (- most-positive-fixnum +interior-coded-max-integer+ 1))
332+
(unexpected-data "unsigned fixnum/interior" fixnum))
333333
(truly-the fixnum fixnum)))
334334
(otherwise (unexpected-data "tag for unsigned fixnum" tag)))
335335
+interior-coded-max-integer+ 1)))))

src/objects.lisp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,12 +291,14 @@
291291
(if (< num-slots 0) ; it's a reference id, look it up in our implicit tracking table
292292
(gethash num-slots implicit-eql-refs)
293293
(progn
294-
(check-if-too-much-data (read-storage-max-to-read storage) (* 8 num-slots))
294+
(if (> num-slots (ash most-positive-fixnum -3))
295+
(unexpected-data "too many slots in object-info" num-slots)
296+
(check-if-too-much-data (read-storage-max-to-read storage) (* 8 num-slots)))
295297
(let ((slot-name-vector (make-array num-slots))
296298
(type (funcall restore-object))
297299
(ref-id (- (the fixnum (incf (the fixnum (car implicit-ref-id)))))))
298300
(unless (symbolp type)
299-
(unexpected-data "symbol" type))
301+
(unexpected-data "expected a symbol"))
300302
;; No circularity possible below as these are symbols
301303
(loop for idx fixnum from 0 below num-slots
302304
do (setf (svref slot-name-vector idx) (funcall restore-object)))
@@ -385,7 +387,7 @@
385387
(declare (type function restore-object) (ignorable storage) (optimize speed safety))
386388
(let ((object-info (funcall restore-object)))
387389
(unless (object-info-p object-info)
388-
(unexpected-data "object-info" object-info))
390+
(unexpected-data "expected an object-info"))
389391
(let* ((specialized-deserializer (object-info-specialized-deserializer object-info))
390392
(constructor (object-info-specialized-constructor object-info)))
391393
(cond

src/pathname.lisp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@
2424
:name (funcall restore-object)
2525
:type (funcall restore-object)
2626
:version (funcall restore-object))
27-
(error (e) (unexpected-data "pathname" e))))
27+
(error () (unexpected-data "pathname malformed"))))

src/reference-coding.lisp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
(+ (- +minimum-untagged-signed-integer+)
4545
(truly-the fixnum number)
4646
1 +reference-two-byte-max-ref-id+))
47-
(unexpected-data "fixnum" number)))
47+
(unexpected-data "reference tag not valid")))
4848

4949
(declaim (inline encode-reference-direct))
5050
(defun encode-reference-direct (ref-index)

src/reference-count.lisp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
(defmethod action ((code (eql +set-reference-action-code+)) storage references restore-object)
2020
(let ((num-refs (restore-tagged-unsigned-fixnum storage)))
2121
#+info-cbs(format t "This file has ~A references~%" num-refs)
22+
(unless (<= 0 num-refs (ash most-positive-fixnum -3))
23+
(unexpected-data "num-refs stored in file invalid"))
2224
(check-if-too-much-data (read-storage-max-to-read storage) (* 8 num-refs))
2325
(values (setf (references-vector references) (make-array num-refs :initial-element nil))
2426
:ignore)))

0 commit comments

Comments
 (0)