🐛 Add max-object-size guard to read-obj! in v1 parser (#11018)

Prevent unbounded memory allocation when a crafted binfile specifies
an excessively large object size. Apply the same 100 MiB limit that
read-stream! already enforces.

AI-assisted-by: mimo-v2.5
This commit is contained in:
Andrey Antukh 2026-08-05 17:40:58 +02:00 committed by GitHub
parent fb07273897
commit 689d3a1be2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 32 additions and 1 deletions

View File

@ -174,6 +174,10 @@
(assert-mark m :obj)
(let [size (read-long! input)]
(assert (pos? size) "incorrect header size found on reading header")
(when (> size bfc/max-object-size)
(ex/raise :type :validation
:code :max-file-size-reached
:hint (dm/str "unable to import object with size " size " bytes")))
(let [buff (byte-array size)]
(read-bytes! input buff)
(fres/decode buff)))))

View File

@ -8,6 +8,7 @@
"Internal binfile test, no RPC involved"
(:require
[app.binfile.common :as bfc]
[app.binfile.v1 :as v1]
[app.binfile.v3 :as v3]
[app.common.features :as cfeat]
[app.common.files.validate :as cfv]
@ -25,7 +26,10 @@
[clojure.test :as t]
[cuerdas.core :as str]
[datoteka.fs :as fs]
[datoteka.io :as io]))
[datoteka.io :as io])
(:import
java.io.ByteArrayInputStream
java.io.DataInputStream))
(t/use-fixtures :once th/state-init)
(t/use-fixtures :each th/database-reset)
@ -202,3 +206,26 @@
(v3/import-files!))]
(t/is (= (count result) 1))
(t/is (every? uuid? result)))))
(t/deftest read-obj-rejects-oversized-buffer
;; N1-07: read-obj! must reject objects exceeding max-object-size
;; before attempting to allocate the buffer
(let [size (+ bfc/max-object-size 1)
baos (java.io.ByteArrayOutputStream. 17)
dos (java.io.DataOutputStream. baos)]
(.writeByte dos 5)
(.writeLong dos (long size))
(.flush dos)
(let [input (java.io.DataInputStream.
(ByteArrayInputStream. (.toByteArray baos)))]
(binding [v1/*position* (atom 0)]
(let [out (try
(v1/read-obj! input)
nil
(catch clojure.lang.ExceptionInfo e
(ex-data e)))]
;; Without the guard, read-obj! will either OOM or proceed
;; to read-bytes! on a truncated stream (no :max-file-size-reached).
;; With the guard, it raises :validation :max-file-size-reached.
(t/is (= :validation (:type out)))
(t/is (= :max-file-size-reached (:code out))))))))