Skip to content

Commit

Permalink
Zlib.inflate: detect truncated input instead of looping
Browse files Browse the repository at this point in the history
Truncated input can cause `inflate` to produce no output and to return
"not finished" infinitely.

Detect this case and fail cleanly with an exception.

Note: it might be enough to fail at the first time `inflate` returns
"not finished but zero output produced".  Here we retry a few times
before failing, just in case.
  • Loading branch information
xavierleroy committed Sep 14, 2024
1 parent 72080af commit c152751
Showing 1 changed file with 12 additions and 4 deletions.
16 changes: 12 additions & 4 deletions zlib.ml
Original file line number Diff line number Diff line change
Expand Up @@ -106,22 +106,30 @@ let uncompress ?(header = true) refill flush =
let rec uncompr inpos inavail =
if inavail = 0 then begin
let incount = refill inbuf in
if incount = 0 then uncompr_finish true else uncompr 0 incount
if incount = 0 then uncompr_finish 0 else uncompr 0 incount
end else begin
let (finished, used_in, used_out) =
inflate zs inbuf inpos inavail outbuf 0 buffer_size Z_SYNC_FLUSH in
flush outbuf used_out;
if not finished then uncompr (inpos + used_in) (inavail - used_in)
end
and uncompr_finish first_finish =
and uncompr_finish num_round =
(* Gotcha: if there is no header, inflate requires an extra "dummy" byte
after the compressed stream in order to complete decompression
and return finished = true. *)
let dummy_byte = if first_finish && not header then 1 else 0 in
let dummy_byte = if num_round = 0 && not header then 1 else 0 in
let (finished, _, used_out) =
inflate zs inbuf 0 dummy_byte outbuf 0 buffer_size Z_SYNC_FLUSH in
flush outbuf used_out;
if not finished then uncompr_finish false
if finished then ()
else if used_out > 0 then uncompr_finish 1
else if num_round < 10 then uncompr_finish (num_round + 1)
else
(* Gotcha: truncated input can cause an infinite loop where
[inflate] doesn't produce output and never returns "finished".
Raise an error after too many calls to [inflate] that produced
no output. *)
raise(Error("Zlib.uncompress", "truncated input data"))
in
uncompr 0 0;
inflate_end zs

0 comments on commit c152751

Please sign in to comment.