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

lib/zlib: fix inflating zlib streams on s390

Decompressing zlib streams on s390 fails with "incorrect data check"
error.

Userspace zlib checks inflate_state.flags in order to byteswap checksums
only for zlib streams, and s390 hardware inflate code, which was ported
from there, tries to match this behavior. At the same time, kernel zlib
does not use inflate_state.flags, so it contains essentially random
values. For many use cases either zlib stream is zeroed out or checksum
is not used, so this problem is masked, but at least SquashFS is still
affected.

Fix by always passing a checksum to and from the hardware as is, which
matches zlib_inflate()'s expectations.

Link: https://lkml.kernel.org/r/20201215155551.894884-1-iii@linux.ibm.com
Fixes: 126196100063 ("lib/zlib: add s390 hardware support for kernel zlib_inflate")
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Tested-by: Christian Borntraeger <borntraeger@de.ibm.com>
Acked-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Cc: <stable@vger.kernel.org> [5.6+]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Ilya Leoshkevich and committed by
Linus Torvalds
f0bb29e8 36845663

+2 -2
+2 -2
lib/zlib_dfltcc/dfltcc_inflate.c
··· 125 125 param->ho = (state->write - state->whave) & ((1 << HB_BITS) - 1); 126 126 if (param->hl) 127 127 param->nt = 0; /* Honor history for the first block */ 128 - param->cv = state->flags ? REVERSE(state->check) : state->check; 128 + param->cv = state->check; 129 129 130 130 /* Inflate */ 131 131 do { ··· 138 138 state->bits = param->sbb; 139 139 state->whave = param->hl; 140 140 state->write = (param->ho + param->hl) & ((1 << HB_BITS) - 1); 141 - state->check = state->flags ? REVERSE(param->cv) : param->cv; 141 + state->check = param->cv; 142 142 if (cc == DFLTCC_CC_OP2_CORRUPT && param->oesc != 0) { 143 143 /* Report an error if stream is corrupted */ 144 144 state->mode = BAD;