Module Name: src Committed By: drochner Date: Thu Feb 17 17:10:18 UTC 2011
Modified Files: src/sys/opencrypto: deflate.c Log Message: The decompressor in sys/net/zlib.c has a bug: It returns Z_BUF_ERROR after a successful decompression in rare cases. A necessary but not sufficient condition seems to be that the decompressed data end exactly at the end of an allocated output buffer. (I can reproduce this reliably with a userland program built against kernel zlib. Userland libz is much newer and not affected.) Since kernel zlib is based on an old version and heavily modified, I don't dare to touch it. So catch this case in the wrapper. Being here, reorder deflate/inflate error handling and add comments to make understandable what is tested and why. To generate a diff of this commit: cvs rdiff -u -r1.15 -r1.16 src/sys/opencrypto/deflate.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/opencrypto/deflate.c diff -u src/sys/opencrypto/deflate.c:1.15 src/sys/opencrypto/deflate.c:1.16 --- src/sys/opencrypto/deflate.c:1.15 Wed Feb 16 19:08:57 2011 +++ src/sys/opencrypto/deflate.c Thu Feb 17 17:10:18 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: deflate.c,v 1.15 2011/02/16 19:08:57 drochner Exp $ */ +/* $NetBSD: deflate.c,v 1.16 2011/02/17 17:10:18 drochner Exp $ */ /* $FreeBSD: src/sys/opencrypto/deflate.c,v 1.1.2.1 2002/11/21 23:34:23 sam Exp $ */ /* $OpenBSD: deflate.c,v 1.3 2001/08/20 02:45:22 hugh Exp $ */ @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: deflate.c,v 1.15 2011/02/16 19:08:57 drochner Exp $"); +__KERNEL_RCSID(0, "$NetBSD: deflate.c,v 1.16 2011/02/17 17:10:18 drochner Exp $"); #include <sys/types.h> #include <sys/malloc.h> @@ -125,10 +125,22 @@ for (;;) { error = decomp ? inflate(&zbuf, Z_SYNC_FLUSH) : deflate(&zbuf, Z_FINISH); - if (error != Z_OK && error != Z_STREAM_END) + if (error == Z_STREAM_END) /* success */ + break; + /* + * XXX compensate for two problems: + * -Former versions of this code didn't set Z_FINISH + * on compression, so the compressed data are not correctly + * terminated and the decompressor doesn't get Z_STREAM_END. + * Accept such packets for interoperability. + * -sys/net/zlib.c has a bug which makes that Z_BUF_ERROR is + * set after successful decompression under rare conditions. + */ + else if (decomp && (error == Z_OK || error == Z_BUF_ERROR) + && zbuf.avail_in == 0 && zbuf.avail_out != 0) + break; + else if (error != Z_OK) goto bad; - else if (zbuf.avail_in == 0 && zbuf.avail_out != 0) - goto end; else if (zbuf.avail_out == 0) { if (i == len) { len += ZBUF; @@ -146,11 +158,9 @@ buf[i].size = size; zbuf.avail_out = buf[i].size; i++; - } else - goto bad; + } } -end: result = count = zbuf.total_out; if (i != 1) { /* copy everything into one buffer */