Skip to content

Commit

Permalink
Fix length check for gzip files 2^32 bytes or larger.
Browse files Browse the repository at this point in the history
  • Loading branch information
GunnarFarneback committed Oct 8, 2023
1 parent 3c1119c commit eaa54a3
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/Inflate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ function inflate_gzip(source::Vector{UInt8}; headers = nothing,
error("corrupted data, crc check failed")
end
isize = getbits(data, 32)
if isize != length(out)
if isize != length(out) % UInt32
error("corrupted data, length check failed")
end

Expand Down Expand Up @@ -694,7 +694,7 @@ function read_trailer(stream::InflateGzipStream)
error("corrupted data, crc check failed")
end
isize = getbits(stream.data, 32)
if isize != stream.num_bytes
if isize != stream.num_bytes % UInt32
error("corrupted data, length check failed")
end
end
Expand Down
15 changes: 15 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ using Inflate
using CodecZlib: GzipCompressorStream, ZlibCompressorStream,
DeflateCompressorStream, CodecZlib

include("utils.jl")

empty_string = ""
short_string = "This is a short string."
medium_string = read(pathof(Inflate), String)
Expand Down Expand Up @@ -80,5 +82,18 @@ end
keep = true) == s
end

# Test gzip decompression of very large data (>2^32 zeros),
# specifically to stress test the length check.
#
# Note: These tests are disabled unless you manually change to `if
# true`. Since they inflate to 4 GB each they take some time to run
# but more importantly they would put undue memory strain on CI.
@testset "large gzip" begin
if false
@test all(==(0), inflate_gzip(all_zeros_gzip(2^32 + 1)))
@test all(==(0), read(InflateGzipStream(IOBuffer(all_zeros_gzip(2^32 + 1)))))
end
end

# Test failure cases, mostly corrupt data.
include("provoke_errors.jl")
31 changes: 31 additions & 0 deletions test/utils.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
function all_zeros_deflate(min_length)
n = max(0, cld(min_length - 249, 1032))
deflate_start = [0xed, 0xc1, 0x01, 0x01, 0x00, 0x00, 0x00, 0x82,
0x20, 0xff, 0xaf, 0x6e, 0x48, 0x40]
deflate_end = [0xaf, 0x06]
return vcat(deflate_start, zeros(UInt8, n), deflate_end), 249 + n * 1032
end

function minimum_gzip_header()
return [0x1f, 0x8b, # Gzip ID bytes.
0x08, # Compression method (deflate).
0x00, # Flags
0x00, 0x00, 0x00, 0x00, # MTIME
0x00, # Extra flags
0xff] # OS (unknown)
end

function all_zeros_crc(n)
c = Inflate.init_crc()
for i in 1:n
c = Inflate.update_crc(c, 0x00)
end
return Inflate.finish_crc(c)
end

function all_zeros_gzip(min_length)
deflate, n = all_zeros_deflate(min_length)
crc = reinterpret(UInt8, [all_zeros_crc(n)])
len = reinterpret(UInt8, [n % UInt32])
return vcat(minimum_gzip_header(), deflate, crc, len)
end

0 comments on commit eaa54a3

Please sign in to comment.