Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

crypto: deflate - fix spurious -ENOSPC

The code in deflate_decompress_one may erroneously return -ENOSPC even if
it didn't run out of output space. The error happens under this
condition:

- Suppose that there are two input pages, the compressed data fits into
the first page and the zlib checksum is placed in the second page.

- The code iterates over the first page, decompresses the data and fully
fills the destination buffer, zlib_inflate returns Z_OK becuse zlib
hasn't seen the checksum yet.

- The outer do-while loop is iterated again, acomp_walk_next_src sets the
input parameters to the second page containing the checksum.

- We go into the inner do-while loop, execute "dcur =
acomp_walk_next_dst(&walk);". "dcur" is zero, so we break out of the
loop and return -ENOSPC, despite the fact that the decompressed data
fit into the destination buffer.

In order to fix this bug, this commit changes the logic when to report
the -ENOSPC error. We report the error if the destination buffer is empty
*and* if zlib_inflate didn't make any progress consuming the input
buffer. If zlib_inflate consumes the trailing checksum, we see that it
made progress and we will not return -ENOSPC.

Fixes: 08cabc7d3c86 ("crypto: deflate - Convert to acomp")
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Mikulas Patocka and committed by
Herbert Xu
6d89f743 80688afb

+7 -4
+7 -4
crypto/deflate.c
··· 164 164 165 165 do { 166 166 unsigned int dcur; 167 + unsigned long avail_in; 167 168 168 169 dcur = acomp_walk_next_dst(&walk); 169 - if (!dcur) { 170 - out_of_space = true; 171 - break; 172 - } 173 170 174 171 stream->avail_out = dcur; 175 172 stream->next_out = walk.dst.virt.addr; 173 + avail_in = stream->avail_in; 176 174 177 175 ret = zlib_inflate(stream, Z_NO_FLUSH); 176 + 177 + if (!dcur && avail_in == stream->avail_in) { 178 + out_of_space = true; 179 + break; 180 + } 178 181 179 182 dcur -= stream->avail_out; 180 183 acomp_walk_done_dst(&walk, dcur);